diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..5480d6b
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,21 @@
+---
+BasedOnStyle: Google
+IndentWidth: 4
+Language: Cpp
+ColumnLimit: 100
+DerivePointerAlignment: false
+PointerAlignment: Left
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: true
+
+AllowAllParametersOfDeclarationOnNextLine: false
+SortIncludes: false
+SpaceAfterCStyleCast: true
+AllowShortCaseLabelsOnASingleLine: false
+AllowAllArgumentsOnNextLine: false
+AllowShortBlocksOnASingleLine: Never
+AllowShortFunctionsOnASingleLine: None
+BinPackArguments: false
+BinPackParameters: false
+---
+
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..98b720f
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,8 @@
+# Checklist
+
+- [ ] App update process has been followed
+- [ ] Target branch is `develop`
+- [ ] Application version has been bumped
+
+
diff --git a/.github/workflows/build-workflow.yml b/.github/workflows/build-workflow.yml
deleted file mode 100644
index 5ee747a..0000000
--- a/.github/workflows/build-workflow.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-name: Compilation
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
- - develop
- workflow_dispatch:
-
-jobs:
- nano_release_build:
- name: Build release application for NanoS, X and S+
- strategy:
- matrix:
- sdk: ["$NANOS_SDK", "$NANOX_SDK", "$NANOSP_SDK"]
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest
-
- steps:
- - name: Clone
- uses: actions/checkout@v3
-
- - name: Build Everscale
- run: |
- make -j BOLOS_SDK=${{ matrix.sdk }}
-
- - name: Build Venom
- run: |
- make clean
- make -j BOLOS_SDK=${{ matrix.sdk }} CHAIN=venom
diff --git a/.github/workflows/build_and_functional_tests.yml b/.github/workflows/build_and_functional_tests.yml
new file mode 100644
index 0000000..696f27c
--- /dev/null
+++ b/.github/workflows/build_and_functional_tests.yml
@@ -0,0 +1,43 @@
+name: Build and run functional tests using ragger through reusable workflow
+
+# This workflow will build the app and then run functional tests using the Ragger framework upon Speculos emulation.
+# It calls a reusable workflow developed by Ledger's internal developer team to build the application and upload the
+# resulting binaries.
+# It then calls another reusable workflow to run the Ragger tests on the compiled application binary.
+#
+# The build part of this workflow is mandatory, this ensures that the app will be deployable in the Ledger App Store.
+# While the test part of this workflow is optional, having functional testing on your application is mandatory and this workflow and
+# tooling environment is meant to be easy to use and adapt after forking your application
+
+on:
+ workflow_dispatch:
+ inputs:
+ golden_run:
+ type: choice
+ required: true
+ default: 'Raise an error (default)'
+ description: CI behavior if the test snapshots are different than expected.
+ options:
+ - 'Raise an error (default)'
+ - 'Open a PR'
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+
+jobs:
+ build_application:
+ name: Build application using the reusable workflow
+ uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_build.yml@v1
+ with:
+ upload_app_binaries_artifact: "compiled_app_binaries"
+
+ ragger_tests:
+ name: Run ragger tests using the reusable workflow
+ needs: build_application
+ uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_ragger_tests.yml@v1
+ with:
+ download_app_binaries_artifact: "compiled_app_binaries"
+ regenerate_snapshots: ${{ inputs.golden_run == 'Open a PR' }}
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
deleted file mode 100644
index cd28f5d..0000000
--- a/.github/workflows/ci-workflow.yml
+++ /dev/null
@@ -1,97 +0,0 @@
-name: CI
-
-on:
- push:
- branches:
- - master
- pull_request:
- branches:
- - master
- - develop
- workflow_dispatch:
-
-jobs:
- scan-build:
- name: Clang Static Analyzer
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest
-
- steps:
- - uses: actions/checkout@v3
-
- - 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@v3
- if: failure()
- with:
- name: scan-build
- path: scan-build
-
-
- # =====================================================
- # SPECULOS TESTS
- # =====================================================
-
-
- building_for_e2e_speculos_tests:
- name: Building binaries for E2E Speculos tests
- runs-on: ubuntu-latest
- container:
- image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest
-
- steps:
- - uses: actions/checkout@v3
-
- - name: Build testing binaries
- run: |
- mkdir tests/speculos/elfs
- make clean && make -j DEBUG=1 BOLOS_SDK=$NANOS_SDK && mv bin/app.elf tests/speculos/elfs/nanos.elf
- make clean && make -j DEBUG=1 BOLOS_SDK=$NANOX_SDK && mv bin/app.elf tests/speculos/elfs/nanox.elf
- make clean && make -j DEBUG=1 BOLOS_SDK=$NANOSP_SDK && mv bin/app.elf tests/speculos/elfs/nanosp.elf
-
- - name: Upload app binaries
- uses: actions/upload-artifact@v3
- with:
- name: e2e_speculos_elfs
- path: ./tests/speculos/elfs
-
-
- jobs-e2e-speculos-tests:
- name: Speculos tests
- strategy:
- fail-fast: false
- matrix:
- model: ["nanos", "nanox", "nanosp"]
-
- needs: [building_for_e2e_speculos_tests]
- runs-on: ubuntu-latest
-
- steps:
- - name: Clone
- uses: actions/checkout@v3
-
- - name: Create tmp folder for artifacts
- run: mkdir tests/speculos/elfs
-
- - name: Download app binaries
- uses: actions/download-artifact@v3
- with:
- path: tmp/
-
- - name: Gather elfs
- run: cp `find tmp/e2e_speculos_elfs/ -name "*.elf"` tests/speculos/elfs/
-
- - name: Install dependencies
- run: |
- cd tests/speculos
- sudo apt-get update && sudo apt-get install -y qemu-user-static
- pip install -r requirements.txt
-
- - name: Run speculos tests
- run: |
- cd tests/speculos
- # pytest --model ${{ matrix.model }} --path ./elfs/${{ matrix.model }}.elf --display headless
diff --git a/.github/workflows/codeql_checks.yml b/.github/workflows/codeql_checks.yml
new file mode 100644
index 0000000..a0c4c5b
--- /dev/null
+++ b/.github/workflows/codeql_checks.yml
@@ -0,0 +1,45 @@
+name: "CodeQL"
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+ # Excluded path: add the paths you want to ignore instead of deleting the workflow
+ paths-ignore:
+ - '.github/workflows/*.yml'
+ - 'tests/*'
+
+jobs:
+ analyse:
+ name: Analyse
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: ["$NANOX_SDK", "$NANOSP_SDK"]
+ # 'cpp' covers C and C++
+ language: ['cpp']
+ runs-on: ubuntu-latest
+ container:
+ image: ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest
+
+ steps:
+ - name: Clone
+ uses: actions/checkout@v4
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: ${{ matrix.language }}
+ queries: security-and-quality
+
+ # CodeQL will create the database during the compilation
+ - name: Build
+ run: |
+ make BOLOS_SDK=${{ matrix.sdk }}
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v3
diff --git a/.github/workflows/coding_style_checks.yml b/.github/workflows/coding_style_checks.yml
new file mode 100644
index 0000000..7927239
--- /dev/null
+++ b/.github/workflows/coding_style_checks.yml
@@ -0,0 +1,25 @@
+name: Run coding style check through reusable workflow
+
+# This workflow will run linting checks to ensure a level of uniformization among all Ledger applications.
+#
+# The presence of this workflow is mandatory as a minimal level of linting is required.
+# You are however free to modify the content of the .clang-format file and thus the coding style of your application.
+# We simply ask you to not diverge too much from the linting of the everscale application.
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+
+jobs:
+ check_linting:
+ name: Check linting using the reusable workflow
+ uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_lint.yml@v1
+ with:
+ source: './src'
+ extensions: 'h,c'
+ version: 12
diff --git a/.github/workflows/guidelines_enforcer.yml b/.github/workflows/guidelines_enforcer.yml
new file mode 100644
index 0000000..fdaf9f2
--- /dev/null
+++ b/.github/workflows/guidelines_enforcer.yml
@@ -0,0 +1,23 @@
+name: Ensure compliance with Ledger guidelines
+
+# This workflow is mandatory in all applications
+# It calls a reusable workflow guidelines_enforcer developed by Ledger's internal developer team.
+# The successful completion of the reusable workflow is a mandatory step for an app to be available on the Ledger
+# application store.
+#
+# More information on the guidelines can be found in the repository:
+# LedgerHQ/ledger-app-workflows/
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+
+jobs:
+ guidelines_enforcer:
+ name: Call Ledger guidelines_enforcer
+ uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_guidelines_enforcer.yml@v1
diff --git a/.github/workflows/misspellings_checks.yml b/.github/workflows/misspellings_checks.yml
new file mode 100644
index 0000000..5bbdb91
--- /dev/null
+++ b/.github/workflows/misspellings_checks.yml
@@ -0,0 +1,29 @@
+name: Misspellings checks
+
+# This workflow performs some misspelling checks on the repository
+# It is there to help us maintain a level of quality in our codebase and does not have to be kept on forked
+# applications.
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+
+jobs:
+ misspell:
+ name: Check misspellings
+ runs-on: ubuntu-latest
+ steps:
+ - name: Clone
+ uses: actions/checkout@v4
+
+ - name: Check misspellings
+ uses: codespell-project/actions-codespell@v2
+ with:
+ builtin: clear,rare
+ check_filenames: true
+ skip: "*.lock"
diff --git a/.github/workflows/python_client_checks.yml b/.github/workflows/python_client_checks.yml
new file mode 100644
index 0000000..db60fd7
--- /dev/null
+++ b/.github/workflows/python_client_checks.yml
@@ -0,0 +1,41 @@
+name: Checks on the Python client
+
+# This workflow performs some checks on the Python client used by the everscale tests
+# It is there to help us maintain a level of quality in our codebase and does not have to be kept on forked
+# applications.
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - master
+ - main
+ - develop
+ pull_request:
+
+jobs:
+ lint:
+ name: everscale client linting
+ runs-on: ubuntu-latest
+ steps:
+ - name: Clone
+ uses: actions/checkout@v4
+ - name: Installing PIP dependencies
+ run: |
+ pip install pylint
+ pip install -r tests/requirements.txt
+ - name: Lint Python code
+ run: pylint --rc tests/setup.cfg tests/application_client/
+
+ mypy:
+ name: Type checking
+ runs-on: ubuntu-latest
+ steps:
+ - name: Clone
+ uses: actions/checkout@v4
+ - name: Installing PIP dependencies
+ run: |
+ pip install mypy
+ pip install -r tests/requirements.txt
+ - name: Mypy type checking
+ run: mypy tests/application_client/
diff --git a/.gitignore b/.gitignore
index d0ea37a..10a7c4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,3 +16,6 @@ dist
*.DS_Store
client/target
fuzz/cmake-build-fuzz
+
+__pycache__
+snapshots-tmp
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 9f55b85..de01af1 100644
--- a/Makefile
+++ b/Makefile
@@ -1,176 +1,129 @@
-#*******************************************************************************
-# Ledger App
-# (c) 2017 Ledger
+# ****************************************************************************
+# Ledger App Everscale
+# (c) 2023 Ledger SAS.
#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# http://www.apache.org/licenses/LICENSE-2.0
+# http://www.apache.org/licenses/LICENSE-2.0
#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#*******************************************************************************
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ****************************************************************************
ifeq ($(BOLOS_SDK),)
$(error Environment variable BOLOS_SDK is not set)
endif
+
include $(BOLOS_SDK)/Makefile.defines
-APP_LOAD_PARAMS = --curve ed25519
-ifeq ($(TARGET_NAME), TARGET_NANOX)
- APP_LOAD_PARAMS += --appFlags 0x200 # APPLICATION_FLAG_BOLOS_SETTINGS
+########################################
+# Mandatory configuration #
+########################################
+# Application name
+ifeq ($(COIN),VENOM)
+APPNAME = "Venom"
else
- APP_LOAD_PARAMS += --appFlags 0x000
+APPNAME = "Everscale"
endif
-APP_LOAD_PARAMS += $(COMMON_LOAD_PARAMS)
-
-# Pending review parameters
-APP_LOAD_PARAMS += --tlvraw 9F:01
-DEFINES += HAVE_PENDING_REVIEW_SCREEN
-##################
-# Define Version #
-##################
+APP_LOAD_FLAGS=--appFlags 0x200
+# Application version
APPVERSION_M = 1
-APPVERSION_N = 0
-APPVERSION_P = 10
-APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"
-
-###########################
-# Set Chain environnement #
-###########################
-
-ifeq ($(CHAIN),)
-CHAIN=everscale
-endif
-
-SUPPORTED_CHAINS=$(shell find makefile_conf/chain/ -type f -name '*.mk'| sed 's/.*\/\(.*\).mk/\1/g' | sort)
-
-# Check if chain is available
-ifeq ($(shell test -s ./makefile_conf/chain/$(CHAIN).mk && echo -n yes), yes)
-include ./makefile_conf/chain/$(CHAIN).mk
-else
-$(error Unsupported CHAIN - use $(SUPPORTED_CHAINS))
-endif
+APPVERSION_N = 1
+APPVERSION_P = 2
+APPVERSION = "$(APPVERSION_M).$(APPVERSION_N).$(APPVERSION_P)"
-#########
-# Other #
-#########
-
-#prepare hsm generation
-ifeq ($(TARGET_NAME),TARGET_NANOS)
-ICONNAME=icons/nanos_app_$(CHAIN).gif
-else
-ICONNAME=icons/nanox_app_$(CHAIN).gif
-endif
-
-################
-# Default rule #
-################
-all: default
-
-DEFINES += $(DEFINES_LIB)
-DEFINES += APPNAME=\"$(APPNAME)\"
-DEFINES += APPVERSION=\"$(APPVERSION)\"
-DEFINES += LEDGER_MAJOR_VERSION=$(APPVERSION_M) LEDGER_MINOR_VERSION=$(APPVERSION_N) LEDGER_PATCH_VERSION=$(APPVERSION_P)
-DEFINES += OS_IO_SEPROXYHAL
-DEFINES += HAVE_BAGL HAVE_UX_FLOW HAVE_SPRINTF
-DEFINES += HAVE_IO_USB HAVE_L4_USBLIB IO_USB_MAX_ENDPOINTS=6 IO_HID_EP_LENGTH=64 HAVE_USB_APDU
-DEFINES += USB_SEGMENT_SIZE=64
-DEFINES += BLE_SEGMENT_SIZE=32
-DEFINES += HAVE_WEBUSB WEBUSB_URL_SIZE_B=0 WEBUSB_URL=""
-DEFINES += UNUSED\(x\)=\(void\)x
-
-ifeq ($(TARGET_NAME),TARGET_NANOX)
- DEFINES += HAVE_BLE BLE_COMMAND_TIMEOUT_MS=2000 HAVE_BLE_APDU
-endif
-
-ifeq ($(TARGET_NAME),TARGET_NANOS)
- DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=128
-else
- DEFINES += IO_SEPROXYHAL_BUFFER_SIZE_B=300
- DEFINES += HAVE_GLO096
- DEFINES += BAGL_WIDTH=128 BAGL_HEIGHT=64
- DEFINES += HAVE_BAGL_ELLIPSIS
- DEFINES += HAVE_BAGL_FONT_OPEN_SANS_REGULAR_11PX
- DEFINES += HAVE_BAGL_FONT_OPEN_SANS_EXTRABOLD_11PX
- DEFINES += HAVE_BAGL_FONT_OPEN_SANS_LIGHT_16PX
-endif
+# Application source files
+APP_SOURCE_PATH += src
-DEBUG = 0
-ifneq ($(DEBUG),0)
- DEFINES += HAVE_PRINTF
- ifeq ($(TARGET_NAME),TARGET_NANOS)
- DEFINES += PRINTF=screen_printf
- else
- DEFINES += PRINTF=mcu_usb_printf
- endif
+# Application icons following guidelines:
+# https://developers.ledger.com/docs/embedded-app/design-requirements/#device-icon
+ifeq ($(COIN),VENOM)
+ICON_NANOX = icons/app_venom_14px.gif
+ICON_NANOSP = icons/app_venom_14px.gif
+ICON_STAX = icons/app_venom_32px.gif
+ICON_FLEX = icons/app_venom_40px.gif
else
- DEFINES += PRINTF\(...\)=
+ICON_NANOX = icons/app_everscale_14px.gif
+ICON_NANOSP = icons/app_everscale_14px.gif
+ICON_STAX = icons/app_everscale_32px.gif
+ICON_FLEX = icons/app_everscale_40px.gif
endif
-##############
-# Compiler #
-##############
-ifneq ($(BOLOS_ENV),)
-$(info BOLOS_ENV=$(BOLOS_ENV))
-CLANGPATH := $(BOLOS_ENV)/clang-arm-fropi/bin/
-GCCPATH := $(BOLOS_ENV)/gcc-arm-none-eabi-5_3-2016q1/bin/
+# Application allowed derivation curves.
+# Possibles curves are: secp256k1, secp256r1, ed25519 and bls12381g1
+# If your app needs it, you can specify multiple curves by using:
+# `CURVE_APP_LOAD_PARAMS = `
+CURVE_APP_LOAD_PARAMS = ed25519
+
+# Application allowed derivation paths.
+# You should request a specific path for your app.
+# This serve as an isolation mechanism.
+# Most application will have to request a path according to the BIP-0044
+# and SLIP-0044 standards.
+# If your app needs it, you can specify multiple path by using:
+# `PATH_APP_LOAD_PARAMS = "44'/1'" "45'/1'"`
+PATH_APP_LOAD_PARAMS = "44'/396'" # purpose=coin(44) / coin_type=Testnet(1)
+
+# Setting to allow building variant applications
+# - is the name of the parameter which should be set
+# to specify the variant that should be build.
+# - a list of variant that can be build using this app code.
+# * It must at least contains one value.
+# * Values can be the app ticker or anything else but should be unique.
+VARIANT_PARAM = COIN
+
+
+ifeq ($(COIN),VENOM)
+VARIANT_VALUES = VENOM
else
-$(info BOLOS_ENV is not set: falling back to CLANGPATH and GCCPATH)
-endif
-ifeq ($(CLANGPATH),)
-$(info CLANGPATH is not set: clang will be used from PATH)
-endif
-ifeq ($(GCCPATH),)
-$(info GCCPATH is not set: arm-none-eabi-* will be used from PATH)
-endif
-
-CC := $(CLANGPATH)clang
-CFLAGS += -O3 -Os
-AS := $(GCCPATH)arm-none-eabi-gcc
-LD := $(GCCPATH)arm-none-eabi-gcc
-LDFLAGS += -O3 -Os
-LDLIBS += -lm -lgcc -lc
-
-# import rules to compile glyphs(/pone)
-include $(BOLOS_SDK)/Makefile.glyphs
-
-### variables processed by the common makefile.rules of the SDK to grab source files and include dirs
-APP_SOURCE_PATH += src
-SDK_SOURCE_PATH += lib_stusb lib_stusb_impl lib_ux
-
-ifeq ($(TARGET_NAME),TARGET_NANOX)
- SDK_SOURCE_PATH += lib_blewbxx lib_blewbxx_impl
-endif
-
-WITH_U2F=0
-ifneq ($(WITH_U2F),0)
- DEFINES += HAVE_U2F HAVE_IO_U2F
- DEFINES += U2F_PROXY_MAGIC=\"~$(COIN)\"
- SDK_SOURCE_PATH += lib_u2f
+VARIANT_VALUES = EVER
endif
-load: all load-only
-load-only:
- python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS)
-
-load-offline: all
- python3 -m ledgerblue.loadApp $(APP_LOAD_PARAMS) --offline
-
-delete:
- python3 -m ledgerblue.deleteApp $(COMMON_DELETE_PARAMS)
-
-# import generic rules from the sdk
-include $(BOLOS_SDK)/Makefile.rules
-
-#add dependency on custom makefile filename
-dep/%.d: %.c Makefile
-
-listvariants:
- @echo VARIANTS CHAIN $(SUPPORTED_CHAINS)
+# Enabling DEBUG flag will enable PRINTF and disable optimizations
+DEBUG = 1
+
+########################################
+# Application custom permissions #
+########################################
+# See SDK `include/appflags.h` for the purpose of each permission
+#HAVE_APPLICATION_FLAG_DERIVE_MASTER = 1
+#HAVE_APPLICATION_FLAG_GLOBAL_PIN = 1
+#HAVE_APPLICATION_FLAG_BOLOS_SETTINGS = 1
+#HAVE_APPLICATION_FLAG_LIBRARY = 1
+
+########################################
+# Application communication interfaces #
+########################################
+ENABLE_BLUETOOTH = 1
+#ENABLE_NFC = 1
+# ENABLE_NBGL_FOR_NANO_DEVICES = 1
+
+########################################
+# NBGL custom features #
+########################################
+ENABLE_NBGL_QRCODE = 1
+#ENABLE_NBGL_KEYBOARD = 1
+#ENABLE_NBGL_KEYPAD = 1
+
+########################################
+# Features disablers #
+########################################
+# These advanced settings allow to disable some feature that are by
+# default enabled in the SDK `Makefile.standard_app`.
+#DISABLE_STANDARD_APP_FILES = 1
+#DISABLE_DEFAULT_IO_SEPROXY_BUFFER_SIZE = 1 # To allow custom size declaration
+#DISABLE_STANDARD_APP_DEFINES = 1 # Will set all the following disablers
+#DISABLE_STANDARD_SNPRINTF = 1
+#DISABLE_STANDARD_USB = 1
+#DISABLE_STANDARD_WEBUSB = 1
+#DISABLE_DEBUG_LEDGER_ASSERT = 1
+#DISABLE_DEBUG_THROW = 1
+
+include $(BOLOS_SDK)/Makefile.standard_app
diff --git a/README.md b/README.md
index b81cb7b..57f58a6 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,9 @@
-
+[](https://github.com/blooo-io/app-everscale/actions/workflows/guidelines_enforcer.yml)
+
+[](https://github.com/blooo-io/app-everscale/actions/workflows/build_and_functional_tests.yml)
# Everscale app for Ledger Wallet
@@ -13,188 +15,252 @@
This app adds support for the Everscale tokens to Ledger hardware wallets.
Current Features:
+
- Pubkey queries
- Address queries
- Sign transaction hash
-- Parse, display and sign Everscale transaction
+- Parse, display and sign Everscale transaction
-## Build and load application
-* [Install Docker](https://docs.docker.com/get-docker/)
-* For Linux hosts, install the Ledger [udev rules](https://github.com/LedgerHQ/udev-rules)
+## Quick start guide
-1. Pull the default image
-```
-docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-```
+### With VSCode
-2. Compile your app in the container
-* For Nano S
-```bash
-$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make
-```
+You can quickly setup a convenient environment to build and test your application
+by using [Ledger's VSCode developer tools extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools)
+which leverages the [ledger-app-dev-tools](https://github.com/LedgerHQ/ledger-app-builder/pkgs/container/ledger-app-builder%2Fledger-app-dev-tools)
+docker image.
-* For Nano X
-```bash
-$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-root@656be163fe84:/app# BOLOS_SDK=$NANOX_SDK make
-```
+It will allow you, whether you are developing on macOS, Windows or Linux to quickly **build** your apps,
+**test** them on **Speculos** and **load** them on any supported device.
-* For Nano S+
-```bash
-$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-root@656be163fe84:/app# BOLOS_SDK=$NANOSP_SDK make
-```
+- Install and run [Docker](https://www.docker.com/products/docker-desktop/).
+- Make sure you have an X11 server running :
+ - On Ubuntu Linux, it should be running by default.
+ - On macOS, install and launch [XQuartz](https://www.xquartz.org/)
+ (make sure to go to XQuartz > Preferences > Security and check "Allow client connections").
+ - On Windows, install and launch [VcXsrv](https://sourceforge.net/projects/vcxsrv/)
+ (make sure to configure it to disable access control).
+- Install [VScode](https://code.visualstudio.com/download) and add [Ledger's extension](https://marketplace.visualstudio.com/items?itemName=LedgerHQ.ledger-dev-tools).
+- Open a terminal and clone `app-everscale` with `git clone git@github.com:blooo-io/app-everscale.git`.
+- Open the `app-everscale` folder with VSCode.
+- Use Ledger extension's sidebar menu or open the tasks menu with `ctrl + shift + b`
+ (`command + shift + b` on a Mac) to conveniently execute actions :
+ - Build the app for the device model of your choice with `Build`.
+ - Test your binary on [Speculos](https://github.com/LedgerHQ/speculos) with `Run with Speculos`.
+ - You can also run functional tests, load the app on a physical device, and more.
-3. Code static analysis
-The Docker images include the [Clang Static Analyzer](https://clang-analyzer.llvm.org/), which can be invoked with:
-```bash
-$ docker run --rm -ti -v "$(realpath .):/app" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make scan-build
-```
+:information_source: The terminal tab of VSCode will show you what commands the extension runs behind the scene.
-4. Load the app on a physical device
+### With a terminal
-:warning: Only Nano S and Nano S+ devices allow application side-loading. This section will not work with a Nano X.
+The [ledger-app-dev-tools](https://github.com/LedgerHQ/ledger-app-builder/pkgs/container/ledger-app-builder%2Fledger-app-dev-tools)
+docker image contains all the required tools and libraries to **build**, **test** and **load** an application.
-To load the app from the container, you will need additional docker arguments in order to allow Docker to access your USB port.
-Your physical device must be connected, unlocked and the screen showing the dashboard (not inside an application). Same as for compilation, `BOLOS_SDK` variable is used to specify the target device. Use the following docker command to load the app (here for Nano S device) :
+You can download it from the ghcr.io docker repository:
-```bash
-$ docker run --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" --user $(id -u $USER):$(id -g $USER) ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder:latest
-root@656be163fe84:/app# BOLOS_SDK=$NANOS_SDK make load
+```shell
+sudo docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest
```
-## Fuzzing
+You can then enter this development environment by executing the following command
+from the directory of the application `git` repository:
-* Build docker image
-```bash
-cd fuzz && docker build -t ledger-app-fuzzer .
-```
+#### Linux (Ubuntu)
-* Build fuzzer
-```bash
-docker run --rm -ti -v "$(realpath .):/app" ledger-app-fuzzer:latest
-root@72edae7503e3:/# cd /app/fuzz && ./build.sh
+```shell
+sudo docker run --rm -ti --user "$(id -u):$(id -g)" --privileged -v "/dev/bus/usb:/dev/bus/usb" -v "$(realpath .):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest
```
-* Run fuzzer
-```bash
-root@72edae7503e3:/app/fuzz/cmake-build-fuzz# cd cmake-build-fuzz && mkdir out && ./fuzzer
+#### macOS
+
+```shell
+sudo docker run --rm -ti --user "$(id -u):$(id -g)" --privileged -v "$(pwd -P):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest
```
-## Example of Ledger wallet functionality
+#### Windows (with PowerShell)
-**Install Rust to compile client to interact with Everscale Ledger app**
-```bash
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+```shell
+docker run --rm -ti --privileged -v "$(Get-Location):/app" ghcr.io/ledgerhq/ledger-app-builder/ledger-app-dev-tools:latest
```
-**List of Everscale wallets**
-```bash
-cargo run --manifest-path client/Cargo.toml get-wallets
-```
+The application's code will be available from inside the docker container,
+you can proceed to the following compilation steps to build your app.
-**Request public key**
-```bash
-cargo run --manifest-path client/Cargo.toml get-pubkey --account ${LEDGER_ACCOUNT_NUMBER}
-```
+## Compilation and load
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml get-pubkey --account 0
-```
+To easily setup a development environment for compilation and loading on a physical device,
+you can use the [VSCode integration](#with-vscode) whether you are on Linux, macOS or Windows.
-**Request address**
-```bash
-cargo run --manifest-path client/Cargo.toml get-address --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE}
-# send some EVER's to the this address (about 1 should be enough)
-```
+If you prefer using a terminal to perform the steps manually, you can use the guide below.
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml get-address --account 0 --wallet EverWallet
-```
+### Compilation
-**Check balance**
-```bash
-cargo run --manifest-path client/Cargo.toml get-balance --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE}
-```
+Setup a compilation environment by following the [shell with docker approach](#with-a-terminal).
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml get-balance --account 0 --wallet EverWallet
+From inside the container, use the following command to build the app :
+
+```shell
+make DEBUG=1 # compile optionally with PRINTF
```
-**Deploy wallet**
-It only applies to Multisig wallets
-```bash
-cargo run --manifest-path client/Cargo.toml deploy --account ${LEDGER_ACCOUNT_NUMBER} -wallet ${WALLET_TYPE}
+You can choose which device to compile and load for by setting the `BOLOS_SDK` environment variable
+to the following values :
+
+- `BOLOS_SDK=$NANOX_SDK`
+- `BOLOS_SDK=$NANOSP_SDK`
+- `BOLOS_SDK=$STAX_SDK`
+- `BOLOS_SDK=$FLEX_SDK`
+
+By default this variable is set to build/load for Nano S+.
+
+### Loading on a physical device
+
+This step will vary slightly depending on your platform.
+
+:information_source: Your physical device must be connected, unlocked and the screen showing the dashboard
+(not inside an application).
+
+#### Linux (Ubuntu)
+
+First make sure you have the proper udev rules added on your host :
+
+```shell
+# Run these commands on your host, from the app's source folder.
+sudo cp .vscode/20-ledger.ledgerblue.rules /etc/udev/rules.d/
+sudo udevadm control --reload-rules
+sudo udevadm trigger
```
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml deploy --account 0 --wallet Multisig2_1
+Then once you have [opened a terminal](#with-a-terminal) in the `app-builder` image and [built the app](#compilation-and-load)
+for the device you want, run the following command :
+
+```shell
+# Run this command from the app-builder container terminal.
+make load # load the app on a Nano S+ by default
```
-**Send EVER transaction**
-```bash
-cargo run --manifest-path client/Cargo.toml send-transaction \
- --account ${LEDGER_ACCOUNT_NUMBER} \
- --wallet ${WALLET_TYPE} \
- --amount ${AMOUNT} \
- --address ${RECIPIENT_ADDRESS}
+[Setting the BOLOS_SDK environment variable](#compilation-and-load) will allow you to load on whichever supported
+device you want.
+
+#### macOS / Windows (with PowerShell)
+
+:information_source: It is assumed you have [Python](https://www.python.org/downloads/) installed on your computer.
+
+Run these commands on your host from the app's source folder once you have [built the app](#compilation-and-load)
+for the device you want :
+
+```shell
+# Install Python virtualenv
+python3 -m pip install virtualenv
+# Create the 'ledger' virtualenv
+python3 -m virtualenv ledger
```
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml send-transaction \
- --account 0 \
- --wallet Multisig2_1 \
- --amount 0.1 \
- --address 0:7094fc3cb69fa1b7bde8e830e2cd74bc9455d93561ce2c562182215686eb45e2
+Enter the Python virtual environment
+
+- macOS : `source ledger/bin/activate`
+- Windows : `.\ledger\Scripts\Activate.ps1`
+
+```shell
+# Install Ledgerblue (tool to load the app)
+python3 -m pip install ledgerblue
+# Load the app.
+python3 -m ledgerblue.runScript --scp --fileName bin/app.apdu --elfFile bin/app.elf
```
-**Get list of supported tokens**
-```bash
-cargo run --manifest-path client/Cargo.toml get-tokens
+## Test
+
+The Everscale app comes with functional tests implemented with Ledger's [Ragger](https://github.com/LedgerHQ/ragger)
+test framework.
+
+### macOS / Windows
+
+To test your app on macOS or Windows, it is recommended to use [Ledger's VS Code extension](#with-vscode)
+to quickly setup a working test environment.
+
+You can use the following sequence of tasks and commands (all accessible in the **extension sidebar menu**) :
+
+- `Select build target`
+- `Build app`
+
+Then you can choose to execute the functional tests :
+
+- Use `Run tests`.
+
+Or simply run the app on the Speculos emulator :
+
+- `Run with Speculos`.
+
+### Linux (Ubuntu)
+
+On Linux, you can use [Ledger's VS Code extension](#with-vscode) to run the tests.
+If you prefer not to, open a terminal and follow the steps below.
+
+Install the tests requirements :
+
+```shell
+pip install -r tests/requirements.txt
```
-**Check token balance**
-```bash
-cargo run --manifest-path client/Cargo.toml get-token-balance --account ${LEDGER_ACCOUNT_NUMBER} --wallet ${WALLET_TYPE} --token ${TOKEN_NAME}
+Then you can :
+
+Run the functional tests (here for nanos+ but available for any device once you have built the binaries) :
+
+```shell
+pytest tests/ --tb=short -v --device nanosp
```
-```bash
-# Example
-cargo run --manifest-path client/Cargo.toml get-token-balance --account 0 --wallet EverWallet --token WEVER
+Or run your app directly with Speculos
+
+```shell
+speculos --model nanosp build/nanos2/bin/app.elf
```
-**Send token transaction**
+## Documentation
+
+This follows the specification available in the [`api.md`](doc/api.md)
+
+## Building the application
+
+### Prerequisites
+
+- Install [Node.js](https://nodejs.org) (lts version)
+- Install [Docker](https://docs.docker.com/get-docker/)
+- Setup the Ledger development environment by following the [official documentation](https://developers.ledger.com/docs/nano-app/introduction/)
+- Make sure the Ledger SDK environment variable is properly set:
+ ```
+ export BOLOS_SDK=/path/to/your/sdk
+ ```
+
+### Building
+
+This application can be built in two variants:
+
+- **Everscale** (default)
+- **Venom**
+
+#### Building the Everscale variant (default)
+
```bash
-cargo run --manifest-path client/Cargo.toml send-token-transaction \
- --account ${LEDGER_ACCOUNT_NUMBER} \
- --wallet ${WALLET_TYPE} \
- --amount ${AMOUNT} \
- --address ${RECIPIENT_ADDRESS} \
- --token ${TOKEN_NAME}
+# Build with default configuration (Everscale)
+make
+
+# Or explicitly specify Everscale
+make COIN=EVER
```
+#### Building the Venom variant
+
```bash
-# Example
-cargo run --manifest-path client/Cargo.toml send-token-transaction \
- --account 0 \
- --wallet EverWallet \
- --amount 1.5 \
- --address 0:ed7439e12d67d23fcaf701ff3bd4e30d390c1e8e14f6f40d52089590e28d9c70 \
- --token WEVER
+# Build the Venom variant
+make COIN=VENOM
```
-## Tests
-Some tests require interactive approval on the ledger
+### Loading the application on your device
+
```bash
-cargo run --manifest-path tests/Cargo.toml
+# Connect your Ledger device and run
+make load
```
-## Documentation
-This follows the specification available in the [`api.md`](doc/api.md)
+When building the application, the appropriate icons and application name will be used based on the selected variant.
diff --git a/client/Cargo.lock b/client/Cargo.lock
index 518c0bd..6272886 100644
--- a/client/Cargo.lock
+++ b/client/Cargo.lock
@@ -1,6 +1,6 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
-version = 3
+version = 4
[[package]]
name = "addr2line"
@@ -197,6 +197,12 @@ version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
[[package]]
name = "base64ct"
version = "1.0.1"
@@ -224,9 +230,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.3.3"
+version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
[[package]]
name = "bitvec"
@@ -427,6 +433,7 @@ name = "client"
version = "0.1.0"
dependencies = [
"anyhow",
+ "base64 0.22.1",
"bigdecimal",
"clap",
"ed25519-dalek",
@@ -438,6 +445,7 @@ dependencies = [
"nekoton-contracts",
"nekoton-utils",
"rust_decimal",
+ "serial_test",
"tokio",
"ton_block",
"ton_types",
@@ -583,13 +591,14 @@ dependencies = [
[[package]]
name = "dialoguer"
-version = "0.10.4"
+version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
+checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
dependencies = [
"console",
"shell-words",
"tempfile",
+ "thiserror",
"zeroize",
]
@@ -681,19 +690,17 @@ dependencies = [
[[package]]
name = "everscale-ledger-wallet"
version = "0.1.0"
-source = "git+https://github.com/broxus/everscale-ledger-wallet.git#a481b2fa884e5015e0823c92f7d30489e26b8430"
+source = "git+https://github.com/broxus/everscale-ledger-wallet.git#c3819438b2ba5c054220cab7def1e1ea82ab6c40"
dependencies = [
"anyhow",
"console",
"dialoguer",
"ed25519-dalek",
- "hex",
"hidapi",
"log",
- "num-derive",
+ "num-derive 0.4.2",
"num-traits",
"parking_lot",
- "qstring",
"semver",
"thiserror",
"uriparse",
@@ -1172,9 +1179,9 @@ dependencies = [
[[package]]
name = "lazy_static"
-version = "1.4.0"
+version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
@@ -1492,6 +1499,17 @@ dependencies = [
"syn 1.0.109",
]
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
+]
+
[[package]]
name = "num-integer"
version = "0.1.45"
@@ -1555,9 +1573,9 @@ dependencies = [
[[package]]
name = "once_cell"
-version = "1.18.0"
+version = "1.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e"
dependencies = [
"parking_lot_core",
]
@@ -1614,9 +1632,9 @@ dependencies = [
[[package]]
name = "parking_lot"
-version = "0.12.1"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
@@ -1624,15 +1642,15 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.8"
+version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.5.10",
"smallvec",
- "windows-targets 0.48.1",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -1760,15 +1778,6 @@ dependencies = [
"syn 1.0.109",
]
-[[package]]
-name = "qstring"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
-dependencies = [
- "percent-encoding",
-]
-
[[package]]
name = "quick_cache"
version = "0.3.0"
@@ -1834,6 +1843,15 @@ dependencies = [
"bitflags 1.3.2",
]
+[[package]]
+name = "redox_syscall"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+dependencies = [
+ "bitflags 2.9.0",
+]
+
[[package]]
name = "rend"
version = "0.4.0"
@@ -1946,7 +1964,7 @@ version = "0.38.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.9.0",
"errno",
"libc",
"linux-raw-sys",
@@ -1965,6 +1983,15 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+[[package]]
+name = "scc"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea091f6cac2595aa38993f04f4ee692ed43757035c36e67c180b6828356385b1"
+dependencies = [
+ "sdd",
+]
+
[[package]]
name = "schannel"
version = "0.1.22"
@@ -1980,6 +2007,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+[[package]]
+name = "sdd"
+version = "3.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "584e070911c7017da6cb2eb0788d09f43d789029b5877d3e5ecc8acf86ceee21"
+
[[package]]
name = "seahash"
version = "4.1.0"
@@ -2068,6 +2101,31 @@ dependencies = [
"serde",
]
+[[package]]
+name = "serial_test"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9"
+dependencies = [
+ "futures",
+ "log",
+ "once_cell",
+ "parking_lot",
+ "scc",
+ "serial_test_derive",
+]
+
+[[package]]
+name = "serial_test_derive"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.27",
+]
+
[[package]]
name = "sha2"
version = "0.9.9"
@@ -2187,7 +2245,7 @@ checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998"
dependencies = [
"cfg-if",
"fastrand",
- "redox_syscall",
+ "redox_syscall 0.3.5",
"rustix",
"windows-sys 0.48.0",
]
@@ -2390,7 +2448,7 @@ dependencies = [
"hex",
"log",
"num",
- "num-derive",
+ "num-derive 0.3.3",
"num-traits",
"rand",
"rustc-hash",
@@ -2720,6 +2778,22 @@ dependencies = [
"windows_x86_64_msvc 0.48.0",
]
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
@@ -2732,6 +2806,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
@@ -2744,6 +2824,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
@@ -2756,6 +2842,18 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
@@ -2768,6 +2866,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
@@ -2780,6 +2884,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
@@ -2792,6 +2902,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
@@ -2804,6 +2920,12 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
[[package]]
name = "winreg"
version = "0.10.1"
diff --git a/client/Cargo.toml b/client/Cargo.toml
index a662402..b315765 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -28,4 +28,8 @@ everscale-ledger-wallet = { git = "https://github.com/broxus/everscale-ledger-wa
nekoton = { git = "https://github.com/broxus/nekoton.git", default-features = false }
nekoton-abi = { git = "https://github.com/broxus/nekoton.git" }
nekoton-utils = { git = "https://github.com/broxus/nekoton.git" }
-nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" }
\ No newline at end of file
+nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" }
+
+[dev-dependencies]
+base64 = "0.22"
+serial_test = "3.2.0"
diff --git a/client/src/main.rs b/client/src/main.rs
index 38d9ac3..4a8901f 100644
--- a/client/src/main.rs
+++ b/client/src/main.rs
@@ -1,6 +1,6 @@
use bigdecimal::BigDecimal;
+use std::rc::Rc;
use std::str::FromStr;
-use std::sync::Arc;
use bigdecimal::num_bigint::ToBigInt;
use clap::Parser;
@@ -224,7 +224,7 @@ impl Token {
}
}
-fn get_ledger() -> (Arc, PublicKey) {
+fn get_ledger() -> (Rc, PublicKey) {
let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager");
// Update device list
@@ -459,14 +459,14 @@ fn prepare_multisig_wallet_deploy(
fn prepare_token_body(
tokens: BigUint,
owner: &MsgAddressInt,
- destiantion: &MsgAddressInt,
+ destination: &MsgAddressInt,
) -> anyhow::Result {
let payload: ton_types::Cell = Default::default();
let (function_token, input_token) =
MessageBuilder::new(tip3_1::token_wallet_contract::transfer())
.arg(BigUint128(tokens)) // amount
- .arg(destiantion) // recipient owner wallet
+ .arg(destination) // recipient owner wallet
.arg(BigUint128(INITIAL_BALANCE.into())) // deployWalletValue
.arg(owner) // remainingGasTo
.arg(false) // notify
@@ -523,7 +523,8 @@ async fn main() -> anyhow::Result<()> {
match contract {
Some(contract) => {
let mut balance =
- Decimal::from_u128(contract.account.storage.balance.grams.as_u128()).trust_me();
+ Decimal::from_u128(contract.account.storage.balance.grams.as_u128())
+ .trust_me();
balance.set_scale(EVER_DECIMALS as u32)?;
println!("Balance: {} EVER", balance);
}
diff --git a/client/tests/get_address.rs b/client/tests/get_address.rs
new file mode 100644
index 0000000..a163078
--- /dev/null
+++ b/client/tests/get_address.rs
@@ -0,0 +1,23 @@
+use everscale_ledger_wallet::ledger::WalletType;
+use everscale_ledger_wallet::remote_wallet::RemoteWallet;
+
+use crate::utils::get_ledger;
+
+mod utils;
+
+#[test]
+fn ledger_get_address() -> anyhow::Result<()> {
+ let (ledger, _) = get_ledger();
+
+ ledger.get_address(0, WalletType::WalletV3, false)?;
+ ledger.get_address(0, WalletType::EverWallet, false)?;
+ ledger.get_address(0, WalletType::SafeMultisig, false)?;
+ ledger.get_address(0, WalletType::SafeMultisig24h, false)?;
+ ledger.get_address(0, WalletType::SetcodeMultisig, false)?;
+ ledger.get_address(0, WalletType::BridgeMultisig, false)?;
+ ledger.get_address(0, WalletType::Surf, false)?;
+ ledger.get_address(0, WalletType::Multisig2, false)?;
+ ledger.get_address(0, WalletType::Multisig2_1, false)?;
+
+ Ok(())
+}
diff --git a/client/tests/get_pubkey.rs b/client/tests/get_pubkey.rs
new file mode 100644
index 0000000..4d7442a
--- /dev/null
+++ b/client/tests/get_pubkey.rs
@@ -0,0 +1,16 @@
+use everscale_ledger_wallet::remote_wallet::RemoteWallet;
+
+use crate::utils::get_ledger;
+
+mod utils;
+
+#[test]
+fn ledger_get_pubkey() -> anyhow::Result<()> {
+ let (ledger, _) = get_ledger();
+
+ ledger.get_pubkey(0, false)?;
+ ledger.get_pubkey(1, false)?;
+ ledger.get_pubkey(2, false)?;
+
+ Ok(())
+}
diff --git a/client/tests/sign_message.rs b/client/tests/sign_message.rs
new file mode 100644
index 0000000..302a23f
--- /dev/null
+++ b/client/tests/sign_message.rs
@@ -0,0 +1,57 @@
+use std::str::FromStr;
+
+use ed25519_dalek::Verifier;
+use everscale_ledger_wallet::ledger::SIGN_MAGIC;
+use everscale_ledger_wallet::remote_wallet::RemoteWallet;
+use nekoton::core::models::Expiration;
+use nekoton::core::ton_wallet::wallet_v3::InitData;
+use nekoton::core::ton_wallet::Gift;
+use nekoton_utils::SimpleClock;
+use ton_block::MsgAddressInt;
+
+use crate::utils::{get_ledger, DEFAULT_EXPIRATION_TIMEOUT, WALLET_ID};
+
+mod utils;
+
+// This test requires interactive approval of message signing on the ledger.
+#[test]
+fn ledger_sign_message() -> anyhow::Result<()> {
+ let (ledger, _) = get_ledger();
+
+ let account = 0;
+
+ // Get public key
+ let public_key = ledger.get_pubkey(account, false)?;
+
+ // Transfer parameters
+ let flags = 3;
+ let bounce = true;
+ let amount = 123_456_785_012_345_678;
+ let destination = MsgAddressInt::from_str(
+ "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56",
+ )?;
+
+ let gift = Gift {
+ flags,
+ bounce,
+ destination,
+ amount,
+ body: None,
+ state_init: None,
+ };
+ let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT);
+
+ let init_data = InitData::from_key(&public_key).with_wallet_id(WALLET_ID);
+ let (hash, _) =
+ init_data.make_transfer_payload(vec![gift], expiration.timestamp(&SimpleClock))?;
+
+ let signature = ledger.sign_message(account, hash.as_slice())?;
+
+ let mut message = Vec::with_capacity(SIGN_MAGIC.len() + hash.as_slice().len());
+ message.extend(SIGN_MAGIC.to_vec());
+ message.extend(hash.into_vec());
+
+ assert!(public_key.verify(message.as_slice(), &signature).is_ok());
+
+ Ok(())
+}
diff --git a/tests/src/main.rs b/client/tests/sign_transaction.rs
similarity index 50%
rename from tests/src/main.rs
rename to client/tests/sign_transaction.rs
index dc3140d..203796c 100644
--- a/tests/src/main.rs
+++ b/client/tests/sign_transaction.rs
@@ -1,188 +1,29 @@
use std::borrow::Cow;
-use std::rc::Rc;
use std::str::FromStr;
-use base64::Engine;
-
-use ed25519_dalek::{PublicKey, Verifier, SIGNATURE_LENGTH};
+use base64::Engine;
+use ed25519_dalek::{Verifier, SIGNATURE_LENGTH};
+use everscale_ledger_wallet::ledger::{SignTransactionMeta, WalletType};
+use everscale_ledger_wallet::remote_wallet::RemoteWallet;
use nekoton::core::models::Expiration;
-use nekoton::core::ton_wallet::wallet_v3::InitData;
-use nekoton::core::ton_wallet::Gift;
use nekoton::core::utils::make_labs_unsigned_message;
use nekoton::crypto::Signature;
use nekoton_abi::{BigUint128, MessageBuilder};
use nekoton_utils::{SimpleClock, TrustMe};
+use serial_test::serial;
use ton_block::MsgAddressInt;
use ton_types::{AccountId, UInt256};
-use everscale_ledger_wallet::ledger::{LedgerWallet, SIGN_MAGIC, SignTransactionMeta, WalletType};
-use everscale_ledger_wallet::locator::Manufacturer;
-use everscale_ledger_wallet::remote_wallet::{initialize_wallet_manager, RemoteWallet};
-
-const EVER_DECIMALS: u8 = 9;
-const EVER_TICKER: &str = "EVER";
-
-const USDT_DECIMALS: u8 = 9;
-const USDT_TICKER: &str = "USDT";
-
-const WALLET_ID: u32 = 0x4BA92D8A;
-
-const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec
-
-fn get_ledger() -> (Rc, PublicKey) {
- let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager");
-
- // Update device list
- const NO_DEVICE_HELP: &str = "No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Everscale running";
- wallet_manager.update_devices().expect(NO_DEVICE_HELP);
- assert!(
- !wallet_manager.list_devices().is_empty(),
- "{}",
- NO_DEVICE_HELP
- );
-
- // Fetch the device path and base pubkey of a connected ledger device
- let (base_pubkey, device_path) = wallet_manager
- .list_devices()
- .iter()
- .find(|d| d.manufacturer == Manufacturer::Ledger)
- .cloned()
- .map(|d| (d.pubkey, d.host_device_path))
- .expect("No ledger device detected");
-
- let ledger = wallet_manager.get_ledger(&device_path).expect("get device");
-
- (ledger, base_pubkey)
-}
-
-fn test_ledger_pubkey() -> anyhow::Result<()> {
- let (ledger, _) = get_ledger();
-
- let pubkey = ledger.get_pubkey(0, false)?;
- assert_eq!(
- hex::encode(pubkey.as_bytes()),
- "6775b6a6ba3711a1c9ac1a62cacf62890ad1df5fbe4308dd9a17405c75b57f2e"
- );
-
- let pubkey = ledger.get_pubkey(1, false)?;
- assert_eq!(
- hex::encode(pubkey.as_bytes()),
- "874dbbeb87f22f7c687cf5bfc33dc103d78c4a9c1e63dde53869202458ca7009"
- );
-
- let pubkey = ledger.get_pubkey(2, false)?;
- assert_eq!(
- hex::encode(pubkey.as_bytes()),
- "3ca0c86c268d5e27f80e234cb66dc811afcd277f5882c3208466e1f3c9395b87"
- );
-
- Ok(())
-}
-
-fn test_ledger_address() -> anyhow::Result<()> {
- let (ledger, _) = get_ledger();
-
- let wallet_v3 = ledger.get_address(0, WalletType::WalletV3, false)?;
- assert_eq!(
- hex::encode(wallet_v3),
- "ed7439e12d67d23fcaf701ff3bd4e30d390c1e8e14f6f40d52089590e28d9c70"
- );
-
- let ever_wallet = ledger.get_address(0, WalletType::EverWallet, false)?;
- assert_eq!(
- hex::encode(ever_wallet),
- "3b94dd326f32f5ab14caef0a61d23e716271b20d7e273fc315ea3cfd0023c431"
- );
-
- let safe_multisig = ledger.get_address(0, WalletType::SafeMultisig, false)?;
- assert_eq!(
- hex::encode(safe_multisig),
- "aafa193fdf6c11cd20a0831ae2a33f7ff4a5add95db7b7b30e7ceef6538e2621"
- );
-
- let safe_multisig_24 = ledger.get_address(0, WalletType::SafeMultisig24h, false)?;
- assert_eq!(
- hex::encode(safe_multisig_24),
- "b4f9941d96904c22613581a4d905051f37ef41c5c0b995a60d5ebfc254e57a1a"
- );
-
- let setcode_multisig = ledger.get_address(0, WalletType::SetcodeMultisig, false)?;
- assert_eq!(
- hex::encode(setcode_multisig),
- "7c75e3bff88ec399edc5ee3a31189ccff6fd564ad2708f3e7208d5c899077f9a"
- );
-
- let bridge_multisig = ledger.get_address(0, WalletType::BridgeMultisig, false)?;
- assert_eq!(
- hex::encode(bridge_multisig),
- "95daf2ffc6c780ca4d4ef63495cf86f8a5f011d3e9fa10edb462ecdc64275136"
- );
-
- let surf = ledger.get_address(0, WalletType::Surf, false)?;
- assert_eq!(
- hex::encode(surf),
- "a1297485df8e1608109ef009b02fab5668d16b6eec7f8c763bd4ec6474be40c5"
- );
-
- let multisig2 = ledger.get_address(0, WalletType::Multisig2, false)?;
- assert_eq!(
- hex::encode(multisig2),
- "2bb06296f9c0be8d4290517d33018ea903b5de40504192953bf631f2e8b56b0b"
- );
-
- let multisig2_1 = ledger.get_address(0, WalletType::Multisig2_1, false)?;
- assert_eq!(
- hex::encode(multisig2_1),
- "bcac3b0b6d2b65b29b18c48b72f76eed1d8dfc86b462086e2731948f1a2550b8"
- );
+use crate::utils::{
+ get_ledger, DEFAULT_EXPIRATION_TIMEOUT, EVER_DECIMALS, EVER_TICKER, USDT_DECIMALS, USDT_TICKER,
+};
- Ok(())
-}
+mod utils;
// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_message() -> anyhow::Result<()> {
- let (ledger, _) = get_ledger();
-
- let account = 0;
-
- // Get public key
- let public_key = ledger.get_pubkey(account, false)?;
-
- // Transfer parameters
- let flags = 3;
- let bounce = true;
- let amount = 123_456_785_012_345_678;
- let destination = MsgAddressInt::from_str(
- "0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56",
- )?;
-
- let gift = Gift {
- flags,
- bounce,
- destination,
- amount,
- body: None,
- state_init: None,
- };
- let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT);
-
- let init_data = InitData::from_key(&public_key).with_wallet_id(WALLET_ID);
- let (hash, _) =
- init_data.make_transfer_payload(vec![gift], expiration.timestamp(&SimpleClock))?;
-
- let signature = ledger.sign_message(account, hash.as_slice())?;
-
- let mut message = Vec::with_capacity(SIGN_MAGIC.len() + hash.as_slice().len());
- message.extend(SIGN_MAGIC.to_vec());
- message.extend(hash.into_vec());
-
- assert!(public_key.verify(message.as_slice(), &signature).is_ok());
-
- Ok(())
-}
-
-// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_send_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_send_transaction() -> anyhow::Result<()> {
let (ledger, _) = get_ledger();
let account = 0;
@@ -212,9 +53,7 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> {
let destination = MsgAddressInt::from_str(
"0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56",
)?;
- let body: ton_types::Cell = ton_types::deserialize_tree_of_cells(&mut base64::engine::general_purpose::STANDARD
- .decode("te6ccgEBAwEAYAABa0ap1+wAAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AEBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJisgCAAA=")?.as_slice())?;
-
+ let body: ton_types::Cell = Default::default();
let expiration = Expiration::Timeout(DEFAULT_EXPIRATION_TIMEOUT);
let (function, input) =
@@ -239,7 +78,7 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> {
// Fake sign
let signature: Signature = [0_u8; 64];
- let signed = unsigned_message.sign_with_pruned_payload(&signature, 2)?;
+ let signed = unsigned_message.sign(&signature)?;
// Extract message body
let mut data = signed.message.body().trust_me();
@@ -255,21 +94,17 @@ fn test_ledger_sign_send_transaction() -> anyhow::Result<()> {
let cell = data.into_cell();
let boc = ton_types::serialize_toc(&cell)?;
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- EVER_DECIMALS,
- EVER_TICKER,
- meta,
- &boc,
- )?;
+ let signature =
+ ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?;
assert!(public_key.verify(message_hash, &signature).is_ok());
Ok(())
}
// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_send_token_transaction() -> anyhow::Result<()> {
let (ledger, _) = get_ledger();
let account = 0;
@@ -295,7 +130,7 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> {
// Transfer parameters
let flags: u8 = 3;
let bounce = true;
- let amount: u64 = 123_456_785_012_345_678;
+ let amount: u64 = 123_456_785_012;
let destination = MsgAddressInt::from_str(
"0:df112b59eb82792623575194c60d2f547c68d54366644a3a5e02b8132f3c4c56",
)?;
@@ -326,7 +161,7 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> {
// Fake sign
let signature: Signature = [0_u8; 64];
- let signed = unsigned_message.sign_with_pruned_payload(&signature, 2)?;
+ let signed = unsigned_message.sign(&signature)?;
// Extract message body
let mut data = signed.message.body().trust_me();
@@ -342,21 +177,17 @@ fn test_ledger_sign_send_msig_transaction() -> anyhow::Result<()> {
let cell = data.into_cell();
let boc = ton_types::serialize_toc(&cell)?;
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- EVER_DECIMALS,
- EVER_TICKER,
- meta,
- &boc,
- )?;
+ let signature =
+ ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?;
assert!(public_key.verify(message_hash, &signature).is_ok());
Ok(())
}
// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_confirm_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_confirm_transaction() -> anyhow::Result<()> {
// let boc = base64::decode("te6ccgEBAQEAOwAAcbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGVwt0ySiJcDVOgdrJKDeYh5nYAwA==")?;
let boc = base64::engine::general_purpose::STANDARD
@@ -376,21 +207,19 @@ fn test_ledger_sign_confirm_transaction() -> anyhow::Result<()> {
let meta = SignTransactionMeta::default();
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- EVER_DECIMALS,
- EVER_TICKER,
- meta,
- &boc,
- )?;
- assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok());
+ let signature =
+ ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?;
+ assert!(public_key
+ .verify(message_hash.as_slice(), &signature)
+ .is_ok());
Ok(())
}
// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_submit_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_submit_transaction() -> anyhow::Result<()> {
let boc = base64::engine::general_purpose::STANDARD
.decode("te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGlca+ySiZfiY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa0ap1+wAAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJisgEAAA=")?;
let cell = ton_types::deserialize_tree_of_cells(&mut boc.as_slice())?;
@@ -407,21 +236,19 @@ fn test_ledger_sign_submit_transaction() -> anyhow::Result<()> {
let meta = SignTransactionMeta::default();
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- USDT_DECIMALS,
- USDT_TICKER,
- meta,
- &boc,
- )?;
- assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok());
+ let signature =
+ ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?;
+ assert!(public_key
+ .verify(message_hash.as_slice(), &signature)
+ .is_ok());
Ok(())
}
// This test requires interactive approval of message signing on the ledger.
-fn test_ledger_sign_burn_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_burn_transaction() -> anyhow::Result<()> {
let boc = base64::engine::general_purpose::STANDARD
.decode("te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA=")?;
@@ -439,22 +266,20 @@ fn test_ledger_sign_burn_transaction() -> anyhow::Result<()> {
let meta = SignTransactionMeta::default();
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- USDT_DECIMALS,
- USDT_TICKER,
- meta,
- &boc,
- )?;
- assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok());
+ let signature =
+ ledger.sign_transaction(account, wallet_type, USDT_DECIMALS, USDT_TICKER, meta, &boc)?;
+ assert!(public_key
+ .verify(message_hash.as_slice(), &signature)
+ .is_ok());
Ok(())
}
// This test requires interactive approval of message signing on the ledger.
// Chunks test
-fn test_ledger_sign_create_token_transaction() -> anyhow::Result<()> {
+#[test]
+#[serial]
+fn ledger_sign_large_transaction() -> anyhow::Result<()> {
let boc = base64::engine::general_purpose::STANDARD
.decode("te6ccgECBgEAASwAIWHw5pxqUFVGcS9uHx4H1Hyxqdv8M0fmFpmbpEK2sRE8qgAAAMVB8+fysn958qZ3MjZAASFlgBpSNW8J55zSsfWhyOd5rDEjZgefz1LcWODp5B1bqgHogAAAAAAAAAAAAAAAJUC+QBA4AiOVEMgafQAACAoJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBQQDKEgBAUZsZIPd9xkGAco8YjJOBZgvCE3wlneY/Wx25kfOjumaAAAoSAEB1IDh09lVWihGkWEM9d9w01WXUrJVmfTd7p+dAZMyU/oAAChIAQGQCROE6sQnHzRREUyjfCGGj+o03d7B++Lo06vNLc44JgAA")?;
@@ -472,42 +297,41 @@ fn test_ledger_sign_create_token_transaction() -> anyhow::Result<()> {
let meta = SignTransactionMeta::default();
- let signature = ledger.sign_transaction(
- account,
- wallet_type,
- EVER_DECIMALS,
- EVER_TICKER,
- meta,
- &boc,
- )?;
- assert!(public_key.verify(message_hash.as_slice(), &signature).is_ok());
+ let signature =
+ ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?;
+ assert!(public_key
+ .verify(message_hash.as_slice(), &signature)
+ .is_ok());
Ok(())
}
-fn main() {
- if let Err(e) = do_run_tests() {
- panic!("{:?}", e)
- }
-}
+#[test]
+#[serial]
+fn ledger_many_msig_custodians_transaction() -> anyhow::Result<()> {
+ // Multisig with 15 custodians
+ let boc = base64::engine::general_purpose::STANDARD
+ .decode("te6ccgECHwEAApQAAmuzuttTXRuI0OTWDTFlZ7FEhWjvr98hhG7NC6AuOtq/lwAAAMrQsOrKM+uyhxXYd8eAAAAHwGACAQAIAAAAAQIDzkAQAwIBIAkEAgEgBgUAQUYLBilvnAvo1CkFGNMQGOqQO13kBQQZKVO/Yx8ei1a5KAIBIAgHAEEULBilvnAvo1CkFGNMQGOqQO13kBQQZKVO/Yx8ei1a5KAAQRAsGKW+cC+jUKQUY0xAY6pA7XeQFBBkpU79jHx6LVrkoAIBIA0KAgEgDAsAQQwsGKW+cC+jUKQUY0zAY6pA7XeQFBBkpU79jHy6LVrAoABBCCwYpb5wL6NQpBRfTEBjqkDtd5AUEGSlTv2MfLotWsCgAgEgDw4AQQQsGKW+cC+jUKQUX0yAY6pA7XeQFBBkpU79jHy6LVrAoABBJuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsCgAgEgGBECASAVEgIBIBQTAEEi7BilvnAvo1CkFF9MwGOoQO13kBQQZKVO/Yx8ui1awKAAQR7sGKW+cC+jUKQUX0zAY6oA7XeQFBBkpU79jHy6LVrAoAIBIBcWAEEa7BilvnAvo1CkFF9MwGOoQO13kBQQZKVO/Yx8ui1awuAAQRbsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4AIBIBwZAgEgGxoAQRLsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4ABBDuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsLgAgEgHh0AQQrsGKW+cC+jUKQUX0zAY6pA7XeQFBBkpU79jHy6LVrC4ABBBuwYpb5wL6NQpBRfTMBjqkDtd5AUEGSlTv2MfLotWsLg")?;
-macro_rules! run {
- ($test:ident) => {
- println!(" >>> Running {} <<<", stringify!($test));
- $test()?;
- };
-}
+ let cell = ton_types::deserialize_tree_of_cells(&mut boc.as_slice())?;
+
+ let message_hash = cell.repr_hash();
+
+ let (ledger, _) = get_ledger();
+
+ let account = 0;
+ let wallet_type = WalletType::SafeMultisig;
+
+ // Get public key
+ let public_key = ledger.get_pubkey(account, false)?;
+
+ let meta = SignTransactionMeta::default();
-fn do_run_tests() -> anyhow::Result<()> {
- run!(test_ledger_pubkey);
- run!(test_ledger_address);
- run!(test_ledger_sign_message);
- run!(test_ledger_sign_send_transaction);
- run!(test_ledger_sign_send_msig_transaction);
- run!(test_ledger_sign_confirm_transaction);
- run!(test_ledger_sign_submit_transaction);
- run!(test_ledger_sign_burn_transaction);
- run!(test_ledger_sign_create_token_transaction);
+ let signature =
+ ledger.sign_transaction(account, wallet_type, EVER_DECIMALS, EVER_TICKER, meta, &boc)?;
+ assert!(public_key
+ .verify(message_hash.as_slice(), &signature)
+ .is_ok());
Ok(())
}
diff --git a/client/tests/utils/mod.rs b/client/tests/utils/mod.rs
new file mode 100644
index 0000000..d670372
--- /dev/null
+++ b/client/tests/utils/mod.rs
@@ -0,0 +1,48 @@
+use std::rc::Rc;
+
+use ed25519_dalek::PublicKey;
+use everscale_ledger_wallet::ledger::LedgerWallet;
+use everscale_ledger_wallet::locator::Manufacturer;
+use everscale_ledger_wallet::remote_wallet::initialize_wallet_manager;
+
+#[allow(dead_code)]
+pub const WALLET_ID: u32 = 0x4BA92D8A;
+
+#[allow(dead_code)]
+pub const EVER_DECIMALS: u8 = 9;
+#[allow(dead_code)]
+pub const EVER_TICKER: &str = "EVER";
+
+#[allow(dead_code)]
+pub const USDT_DECIMALS: u8 = 9;
+#[allow(dead_code)]
+pub const USDT_TICKER: &str = "USDT";
+
+#[allow(dead_code)]
+pub const DEFAULT_EXPIRATION_TIMEOUT: u32 = 60; // sec
+
+pub fn get_ledger() -> (Rc, PublicKey) {
+ let wallet_manager = initialize_wallet_manager().expect("Couldn't start wallet manager");
+
+ // Update device list
+ const NO_DEVICE_HELP: &str = "No Ledger found, make sure you have a unlocked Ledger connected with the Ledger Wallet Everscale running";
+ wallet_manager.update_devices().expect(NO_DEVICE_HELP);
+ assert!(
+ !wallet_manager.list_devices().is_empty(),
+ "{}",
+ NO_DEVICE_HELP
+ );
+
+ // Fetch the device path and base pubkey of a connected ledger device
+ let (base_pubkey, device_path) = wallet_manager
+ .list_devices()
+ .iter()
+ .find(|d| d.manufacturer == Manufacturer::Ledger)
+ .cloned()
+ .map(|d| (d.pubkey, d.host_device_path))
+ .expect("No ledger device detected");
+
+ let ledger = wallet_manager.get_ledger(&device_path).expect("get device");
+
+ (ledger, base_pubkey)
+}
diff --git a/doc/api.md b/doc/api.md
index 49ee42f..0177390 100644
--- a/doc/api.md
+++ b/doc/api.md
@@ -16,7 +16,7 @@ The application interface can be accessed over HID or BLE
## Command APDU
| Field name | Length (bytes) | Description |
-| ---------- |----------------| --------------------------------------------------------------------- |
+| ---------- | -------------- | --------------------------------------------------------------------- |
| CLA | 1 | Instruction class - indicates the type of command |
| INS | 1 | Instruction code - indicates the specific command |
| P1 | 1 | Instruction parameter 1 for the command |
@@ -37,7 +37,7 @@ _This command returns specific application configuration_
##### Command
| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
-| ----- |:-----:| ---: | ---- |:----:|---------:|
+| ----- | :---: | ---: | ---- | :--: | -------: |
| E0 | 01 | 00 | 00 | 00 | variable |
##### Input data
@@ -60,21 +60,20 @@ _This command returns a public key for the given account number_
##### Command
-| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
-| ----- |:-----:|:---------------------------------------------------------------------------------|------| :------: |----------:|
-| E0 | 02 | 00 : return public key
01 : display public key and confirm before returning | 00 | variable | variable |
+| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
+| ----- | :---: | :------------------------------------------------------------------------------ | ---- | :------: | -------: |
+| E0 | 02 | 00 : return public key
01 : display public key and confirm before returning | 00 | variable | variable |
##### Input data
-| _Description_ | _Length_ |
-|-------------------------------------|:--------:|
-| An account number to retrieve | 4 |
-
+| _Description_ | _Length_ |
+| ----------------------------- | :------: |
+| An account number to retrieve | 4 |
##### Output data
| _Description_ | _Length_ |
-| ------------- |:--------:|
+| ------------- | :------: |
| Pubkey length | 1 |
| Pubkey | 32 |
@@ -89,20 +88,20 @@ To avoid blindly signing message hash the application adds a 4-byte prefix [0xFF
##### Command
| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
-| ----- |:-----:| ---: | ---- | :------: |---------:|
+| ----- | :---: | ---: | ---- | :------: | -------: |
| E0 | 03 | 01 | 00 | variable | variable |
##### Input data
-| _Description_ | _Length_ |
-|------------------------------------------|:--------:|
-| An account number to retrieve | 4 |
-| A bytes to sign | 32 |
+| _Description_ | _Length_ |
+| ----------------------------- | :------: |
+| An account number to retrieve | 4 |
+| A bytes to sign | 32 |
##### Output data
| _Description_ | _Length_ |
-|------------------| :------: |
+| ---------------- | :------: |
| Signature length | 1 |
| Signature | 64 |
@@ -115,20 +114,20 @@ _This command returns an address for the given account number_
##### Command
| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
-| ----- |:-----:|:--------------------------------------------------------------------------|------| :------: |---------:|
+| ----- | :---: | :------------------------------------------------------------------------ | ---- | :------: | -------: |
| E0 | 04 | 00 : return address
01 : display address and confirm before returning | 00 | variable | variable |
##### Input data
| _Description_ | _Length_ |
-|-------------------------------|:--------:|
+| ----------------------------- | :------: |
| An account number to retrieve | 4 |
| Wallet number to retrieve | 1 |
##### Output data
| _Description_ | _Length_ |
-|----------------|:--------:|
+| -------------- | :------: |
| Address length | 1 |
| Address | 32 |
@@ -140,14 +139,14 @@ _This command signs a transaction message_
##### Command
-| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
-| ----- |:-----:| ---: | ---- | :------: |---------------:|
-| E0 | 05 | 01 | 0x01 (last chunk)
0x02 (first chunk)
0x00 (single chunk)
0x03 (intermediate chunk) | variable | variable |
+| _CLA_ | _INS_ | _P1_ | _P2_ | _Lc_ | _CData_ |
+| ----- | :---: | ---: | ------------------------------------------------------------------------------------------------- | :------: | -------: |
+| E0 | 05 | 01 | 0x01 (last chunk)
0x02 (first chunk)
0x00 (single chunk)
0x03 (intermediate chunk) | variable | variable |
##### Input data
| _Description_ | _Length_ |
-|--------------------------------------------------------------------------------|:--------:|
+| ------------------------------------------------------------------------------ | :------: |
| An account number to retrieve | 4 |
| Original wallet number to derive address | 1 |
| Decimals | 1 |
@@ -162,10 +161,24 @@ _This command signs a transaction message_
##### Output data
-| _Description_ | _Length_ |
-|-----------------| :------: |
-| Address length | 1 |
-| Signature | 64 |
+| _Description_ | _Length_ |
+| -------------- | :------: |
+| Address length | 1 |
+| Signature | 64 |
+
+## Status Words
+
+The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description.
+
+##### Status Words
+
+| _SW_ | _Description_ |
+| ---- | :-----------------------------------------------: |
+| 6700 | Incorrect length |
+| 6985 | Canceled by user |
+| 6B0x | Invalid request |
+| 6Fxx | Technical problem (Internal error, please report) |
+| 9000 | Normal ending of the command |
## Transport protocol
@@ -214,17 +227,3 @@ The application acts as a GATT server defining service UUID D973F2E0-B19E-11E2-9
When using this service, the client sends requests to the characteristic D973F2E2-B19E-11E2-9E96-0800200C9A66, and gets notified on the characteristic D973F2E1-B19E-11E2-9E96-0800200C9A66 after registering for it.
Requests are encoded using the standard BLE 20 bytes MTU size
-
-## Status Words
-
-The following standard Status Words are returned for all APDUs - some specific Status Words can be used for specific commands and are mentioned in the command description.
-
-##### Status Words
-
-| _SW_ | _Description_ |
-| ---- |:--------------------------------------------------:|
-| 6700 | Incorrect length |
-| 6982 | Security status not satisfied (Canceled by user) |
-| 6B0x | Invalid request |
-| 6Fxx | Technical problem (Internal error, please report) |
-| 9000 | Normal ending of the command |
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..73ecd1e
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,16 @@
+# version: "3.7"
+
+services:
+ nanosp:
+ image: ghcr.io/blooo-io/speculos:latest
+ volumes:
+ - ./bin:/speculos/apps
+ - ./src:/speculos/sources
+ - ./build:/speculos/build
+ ports:
+ - "5000:5000" # api
+ - "40000:40000" # apdu
+ environment:
+ - GDB_DIRECTORY_LIST="/speculos/sources:/speculos/sources/ui:/speculos/sources/handler:"
+ command: "-d --model nanosp build/nanos2/bin/app.elf --display headless --apdu-port 40000"
+ # Add `--vnc-password ""` for macos users to use built-in vnc client.
\ No newline at end of file
diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt
deleted file mode 100644
index 64f22c4..0000000
--- a/fuzz/CMakeLists.txt
+++ /dev/null
@@ -1,57 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-project(NeoFuzzer VERSION 0.1.9 LANGUAGES C)
-
-set(CMAKE_C_STANDARD 11)
-
-# BOLOS SDK
-set(BOLOS_SDK $ENV{BOLOS_SDK})
-add_compile_definitions(IO_HID_EP_LENGTH=64)
-
-find_package(OpenSSL REQUIRED)
-
-# add_compile_definitions(HAVE_HASH HAVE_SHA256)
-include_directories(.
- ../src
- "${BOLOS_SDK}/include"
- "${BOLOS_SDK}/lib_cxng/include"
-)
-
-add_compile_options(-g -O0 -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
-
-# Build with code coverage generation
-if(CODE_COVERAGE)
- if(CMAKE_C_COMPILER_ID MATCHES "(Apple)?[Cc]lang")
- add_compile_options(-fprofile-instr-generate -fcoverage-mapping)
- add_link_options(-fprofile-instr-generate -fcoverage-mapping)
- elseif(CMAKE_C_COMPILER_ID MATCHES "GNU")
- add_compile_options(-fprofile-arcs -ftest-coverage)
- link_libraries(gcov)
- else()
- message(FATAL_ERROR "Unsupported compiler used with code coverage generation")
- endif()
-endif()
-
-# Fuzzer target
-set(APP_SRC_DIR "../src")
-
-set(APP_SOURCES
- ${APP_SRC_DIR}/byte_stream.c
- ${APP_SRC_DIR}/message.c
- ${APP_SRC_DIR}/slice_data.c
- ${APP_SRC_DIR}/contract.c
- ${APP_SRC_DIR}/cell.c
- ${APP_SRC_DIR}/hashmap_label.c
- ${APP_SRC_DIR}/utils.c
-)
-
-add_executable(fuzzer
- fuzzer.c
- os_mocks.c
- ${APP_SOURCES}
-)
-
-target_include_directories(fuzzer PUBLIC ../src)
-target_compile_options(fuzzer PUBLIC -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=undefined)
-target_link_options(fuzzer PUBLIC -fsanitize=fuzzer,address,undefined -fno-sanitize-recover=undefined)
-target_link_libraries(fuzzer OpenSSL::SSL)
diff --git a/fuzz/Dockerfile b/fuzz/Dockerfile
deleted file mode 100644
index a54477a..0000000
--- a/fuzz/Dockerfile
+++ /dev/null
@@ -1,38 +0,0 @@
-FROM ubuntu:22.04
-
-RUN apt update
-RUN apt install -y git cmake clang libssl-dev
-
-# Clone the repository.
-# WARNING: use the latest version of the app and integrate the fuzzer
-RUN git clone https://github.com/qbLedger/ledger-app-everscale.git
-RUN cd ledger-app-everscale && git checkout pr_ready
-
-# Get the sdk
-RUN git clone https://github.com/LedgerHQ/nanos-secure-sdk.git
-
-# Patch the sdk
-RUN echo -e 'diff --git a/include/os_seed.h b/include/os_seed.h\n\
-index 63b12ee..633346b 100644\n\
---- a/include/os_seed.h\n\
-+++ b/include/os_seed.h\n\
-@@ -4,6 +4,8 @@\n\
- ''#include "decorators.h"\n\
- ''#include "lcx_ecfp.h"\n\
- ''#include "os_types.h"\n\
-+#include "ox_ec.h"\n\
-+#include "exceptions.h"\n\
- \n\
- /* ----------------------------------------------------------------------- */\n\
- /* - SEED FEATURE - */\n' > os_seed-fix.patch
-RUN cat /os_seed-fix.patch
-RUN patch -p1 -i /os_seed-fix.patch -d /nanos-secure-sdk/
-
-# Set the BOLOS_SDK env var
-ENV BOLOS_SDK /nanos-secure-sdk/
-
-# Build the fuzzer
-RUN cd ledger-app-everscale/fuzz && ./build.sh
-
-# Run the fuzzer. Here you can specify a pre-existing corpus
-#RUN cd ledger-app-everscale/fuzz/cmake-build-fuzz && mkdir corpus && ./fuzzer corpus/
diff --git a/fuzz/build.sh b/fuzz/build.sh
deleted file mode 100755
index c6ecbd2..0000000
--- a/fuzz/build.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/bash
-set -e
-
-SCRIPTDIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd)"
-BUILDDIR="$SCRIPTDIR/cmake-build-fuzz"
-
-# Compile fuzzer
-rm -rf "$BUILDDIR"
-mkdir "$BUILDDIR"
-cd "$BUILDDIR"
-
-cmake -DCMAKE_C_COMPILER=clang ..
-make clean
-make fuzzer
\ No newline at end of file
diff --git a/fuzz/ux.h b/fuzz/ux.h
deleted file mode 100644
index 65fec9e..0000000
--- a/fuzz/ux.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-#define bagl_element_t int
-#define cx_ecfp_private_key_t int
diff --git a/fuzzing/CMakeLists.txt b/fuzzing/CMakeLists.txt
new file mode 100644
index 0000000..e7f72a5
--- /dev/null
+++ b/fuzzing/CMakeLists.txt
@@ -0,0 +1,60 @@
+cmake_minimum_required(VERSION 3.10)
+
+if(${CMAKE_VERSION} VERSION_LESS 3.10)
+ cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
+endif()
+
+# project information
+project(FuzzTxParser
+ VERSION 1.0
+ DESCRIPTION "Fuzzing of transaction parser"
+ LANGUAGES C)
+
+find_package(OpenSSL REQUIRED)
+
+# guard against bad build-type strings
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Debug")
+endif()
+
+if (NOT CMAKE_C_COMPILER_ID MATCHES "Clang")
+ message(FATAL_ERROR "Fuzzer needs to be built with Clang")
+endif()
+
+if (NOT DEFINED BOLOS_SDK)
+ message(FATAL_ERROR "BOLOS_SDK environment variable not found.")
+endif()
+
+if (NOT DEFINED TARGET_DEVICE)
+ message(FATAL_ERROR "TARGET_DEVICE environment variable not found.")
+endif()
+
+# guard against in-source builds
+if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
+ message(FATAL_ERROR "In-source builds not allowed. Please make a new directory (called a build directory) and run CMake from there. You may need to remove CMakeCache.txt. ")
+endif()
+
+# compatible with ClusterFuzzLite
+if (NOT DEFINED ENV{LIB_FUZZING_ENGINE})
+ set(COMPILATION_FLAGS_ "-g -Wall -fsanitize=fuzzer,address,undefined")
+else()
+ set(COMPILATION_FLAGS_ "$ENV{LIB_FUZZING_ENGINE} $ENV{CXXFLAGS}")
+endif()
+
+add_compile_options(-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION=1)
+
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+add_compile_definitions(IO_HID_EP_LENGTH=64 USB_SEGMENT_SIZE=64 BLE_SEGMENT_SIZE=32)
+
+string(REPLACE " " ";" COMPILATION_FLAGS ${COMPILATION_FLAGS_})
+
+include(extra/TxParser.cmake)
+
+add_executable(fuzzer fuzzer.c os_mocks.c)
+
+target_include_directories(fuzzer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../src)
+
+target_compile_options(fuzzer PUBLIC ${COMPILATION_FLAGS})
+target_link_options(fuzzer PUBLIC ${COMPILATION_FLAGS})
+target_link_libraries(fuzzer PUBLIC txparser OpenSSL::SSL)
diff --git a/fuzzing/Dockerfile b/fuzzing/Dockerfile
new file mode 100644
index 0000000..ea9f967
--- /dev/null
+++ b/fuzzing/Dockerfile
@@ -0,0 +1,19 @@
+FROM ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-legacy:latest
+
+RUN apt update && apt install -y libssl-dev
+
+# Patch SDK
+RUN cd /opt/ledger-secure-sdk && echo -e 'diff --git a/include/os_seed.h b/include/os_seed.h\n\
+index da35f4c5..1f4a224f 100644\n\
+--- a/include/os_seed.h\n\
++++ b/include/os_seed.h\n\
+@@ -6,6 +6,8 @@\n\
+ ''#include "decorators.h"\n\
+ ''#include "lcx_ecfp.h"\n\
+ ''#include "os_types.h"\n\
++#include "ox_ec.h"\n\
++#include "exceptions.h"\n\
+ \n\
+ /* ----------------------------------------------------------------------- */\n\
+ /* - SEED FEATURE - */\n' > os_seed-fix.patch && \
+patch -p1 < os_seed-fix.patch
diff --git a/fuzzing/README.md b/fuzzing/README.md
new file mode 100644
index 0000000..49c3e32
--- /dev/null
+++ b/fuzzing/README.md
@@ -0,0 +1,34 @@
+# Fuzzing on transaction parser
+
+## Compilation
+
+* Build docker image
+
+```
+pushd fuzzing && docker build -t ledger-app-fuzzer . && popd
+```
+
+* Run docker container
+
+```
+docker run --rm -ti --user "$(id -u):$(id -g)" -v "$(realpath .):/app" ledger-app-fuzzer:latest
+
+```
+
+* Build fuzzer inside the container
+
+```
+cd /app/fuzzing && cmake -DBOLOS_SDK=/opt/ledger-secure-sdk -DTARGET_DEVICE=nanos -DCMAKE_C_COMPILER=/usr/bin/clang -Bbuild -H.
+```
+
+then
+
+```
+make -C build
+```
+
+## Run
+
+```
+./build/fuzzer
+```
diff --git a/fuzzing/extra/TxParser.cmake b/fuzzing/extra/TxParser.cmake
new file mode 100644
index 0000000..ec74ef3
--- /dev/null
+++ b/fuzzing/extra/TxParser.cmake
@@ -0,0 +1,37 @@
+# project information
+project(TxParser
+ VERSION 1.0
+ DESCRIPTION "Transaction parser of Everscale app"
+ LANGUAGES C)
+
+# specify C standard
+set(CMAKE_C_STANDARD 11)
+set(CMAKE_C_STANDARD_REQUIRED True)
+set(CMAKE_C_FLAGS_DEBUG
+ "${CMAKE_C_FLAGS_DEBUG} -Wall -Wextra -Wno-unused-function -DFUZZ -pedantic -g -O0"
+)
+
+add_library(txparser
+ ${BOLOS_SDK}/lib_standard_app/format.c
+ ${BOLOS_SDK}/lib_standard_app/buffer.c
+ ${BOLOS_SDK}/lib_standard_app/read.c
+ ${BOLOS_SDK}/lib_standard_app/write.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/byte_stream.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/cell.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/contract.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/hashmap_label.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/message.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/slice_data.c
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/utils.c
+)
+
+set_target_properties(txparser PROPERTIES SOVERSION 1)
+
+target_include_directories(txparser PUBLIC
+ ${BOLOS_SDK}/include
+ ${BOLOS_SDK}/lib_cxng/include
+ ${BOLOS_SDK}/lib_standard_app
+ ${BOLOS_SDK}/target/${TARGET_DEVICE}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src
+ ${CMAKE_CURRENT_SOURCE_DIR}/../src/ui
+)
diff --git a/fuzz/fuzzer.c b/fuzzing/fuzzer.c
similarity index 66%
rename from fuzz/fuzzer.c
rename to fuzzing/fuzzer.c
index a872a4b..e69fa65 100644
--- a/fuzz/fuzzer.c
+++ b/fuzzing/fuzzer.c
@@ -22,15 +22,14 @@
BocContext_t boc_context;
DataContext_t data_context;
-void hex_to_bytes(const char* hex, uint8_t* bytes)
-{
+void hex_to_bytes(const char* hex, uint8_t* bytes) {
size_t len = strlen(hex);
size_t final_len = len / 2;
- for (size_t i=0, j=0; jjmp_buf, exception);
}
-try_context_t *current_context = NULL;
-try_context_t *try_context_get(void) { return current_context; }
+try_context_t* current_context = NULL;
+try_context_t* try_context_get(void) {
+ return current_context;
+}
-try_context_t *try_context_set(try_context_t *ctx) {
- try_context_t *previous_ctx = current_context;
+try_context_t* try_context_set(try_context_t* ctx) {
+ try_context_t* previous_ctx = current_context;
current_context = ctx;
return previous_ctx;
}
@@ -29,9 +31,9 @@ try_context_t *try_context_set(try_context_t *ctx) {
// return CX_OK;
// }
-size_t cx_hash_sha256(const uint8_t *in, size_t len, uint8_t *out, size_t out_len) {
- EVP_MD_CTX *mdctx;
- const EVP_MD *md;
+size_t cx_hash_sha256(const uint8_t* in, size_t len, uint8_t* out, size_t out_len) {
+ EVP_MD_CTX* mdctx;
+ const EVP_MD* md;
unsigned int hash_len;
uint8_t tmpBuf[EVP_MAX_MD_SIZE];
@@ -47,6 +49,6 @@ size_t cx_hash_sha256(const uint8_t *in, size_t len, uint8_t *out, size_t out_le
hash_len = ERR_INVALID_DATA;
else
memcpy(out, tmpBuf, hash_len);
-
+
return hash_len;
}
diff --git a/gdb.sh b/gdb.sh
new file mode 100755
index 0000000..937fa2c
--- /dev/null
+++ b/gdb.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+docker compose up -d
+
+# Wait for the container to start
+until docker inspect -f '{{.State.Status}}' app-everscale-nanosp-1 | grep -q "running"; do
+ sleep 1
+done
+
+docker exec -it app-everscale-nanosp-1 ./tools/debug.sh apps/app.elf
+
+docker compose down
\ No newline at end of file
diff --git a/icons/nanos_app_everscale.gif b/glyphs/app_everscale_16px.gif
similarity index 100%
rename from icons/nanos_app_everscale.gif
rename to glyphs/app_everscale_16px.gif
diff --git a/glyphs/app_everscale_64px.gif b/glyphs/app_everscale_64px.gif
new file mode 100644
index 0000000..5347c2c
Binary files /dev/null and b/glyphs/app_everscale_64px.gif differ
diff --git a/icons/nanos_app_venom.gif b/glyphs/app_venom_16px.gif
similarity index 100%
rename from icons/nanos_app_venom.gif
rename to glyphs/app_venom_16px.gif
diff --git a/glyphs/app_venom_64px.gif b/glyphs/app_venom_64px.gif
new file mode 100644
index 0000000..add4950
Binary files /dev/null and b/glyphs/app_venom_64px.gif differ
diff --git a/icons/nanox_app_everscale.gif b/icons/app_everscale_14px.gif
similarity index 100%
rename from icons/nanox_app_everscale.gif
rename to icons/app_everscale_14px.gif
diff --git a/icons/app_everscale_16px.gif b/icons/app_everscale_16px.gif
new file mode 100644
index 0000000..b362f69
Binary files /dev/null and b/icons/app_everscale_16px.gif differ
diff --git a/icons/app_everscale_32px.gif b/icons/app_everscale_32px.gif
new file mode 100644
index 0000000..516045f
Binary files /dev/null and b/icons/app_everscale_32px.gif differ
diff --git a/icons/app_everscale_40px.gif b/icons/app_everscale_40px.gif
new file mode 100644
index 0000000..2c61a3d
Binary files /dev/null and b/icons/app_everscale_40px.gif differ
diff --git a/icons/nanox_app_venom.gif b/icons/app_venom_14px.gif
similarity index 100%
rename from icons/nanox_app_venom.gif
rename to icons/app_venom_14px.gif
diff --git a/icons/app_venom_16px.gif b/icons/app_venom_16px.gif
new file mode 100644
index 0000000..c98d292
Binary files /dev/null and b/icons/app_venom_16px.gif differ
diff --git a/icons/app_venom_32px.gif b/icons/app_venom_32px.gif
new file mode 100644
index 0000000..df4c621
Binary files /dev/null and b/icons/app_venom_32px.gif differ
diff --git a/icons/app_venom_40px.gif b/icons/app_venom_40px.gif
new file mode 100644
index 0000000..d02fbc1
Binary files /dev/null and b/icons/app_venom_40px.gif differ
diff --git a/ledger_app.toml b/ledger_app.toml
new file mode 100644
index 0000000..7794dab
--- /dev/null
+++ b/ledger_app.toml
@@ -0,0 +1,7 @@
+[app]
+build_directory = "./"
+sdk = "C"
+devices = ["nanos+", "nanox", "flex", "stax"]
+
+[tests]
+pytest_directory = "./tests/"
diff --git a/src/apdu/dispatcher.c b/src/apdu/dispatcher.c
new file mode 100644
index 0000000..4a463d6
--- /dev/null
+++ b/src/apdu/dispatcher.c
@@ -0,0 +1,128 @@
+/*****************************************************************************
+ * Ledger App Everscale.
+ * (c) 2020 Ledger SAS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+#include
+#include
+#include "parser.h"
+
+#include "buffer.h"
+#include "io.h"
+#include "ledger_assert.h"
+#include "apdu_constants.h"
+#include "dispatcher.h"
+#include "globals.h"
+#include "handler/get_app_configuration.h"
+#include "handler/get_public_key.h"
+#include "handler/sign_transaction.h"
+#include "handler/get_address.h"
+#include "handler/sign.h"
+
+int apdu_dispatcher(const command_t* cmd, volatile unsigned int* flags) {
+ LEDGER_ASSERT(cmd != NULL, "NULL cmd");
+
+ if (cmd->cla != CLA) {
+ return io_send_sw(ERR_CLA_NOT_SUPPORTED);
+ }
+
+ buffer_t buf = {0};
+
+ switch (cmd->ins) {
+ case INS_GET_APP_CONFIGURATION:
+ if (cmd->p1 != 0 || cmd->p2 != 0) {
+ return io_send_sw(ERR_WRONG_P1P2);
+ }
+ if (cmd->lc != 0) {
+ return io_send_sw(ERR_WRONG_DATA_LENGTH);
+ }
+
+ return handleGetAppConfiguration();
+ case INS_GET_PUBLIC_KEY:
+ if (cmd->p1 > 1 || cmd->p2 > 0) {
+ return io_send_sw(ERR_WRONG_P1P2);
+ }
+ if (cmd->lc != sizeof(uint32_t)) {
+ return io_send_sw(ERR_WRONG_DATA_LENGTH);
+ }
+
+ if (!cmd->data) {
+ return io_send_sw(ERR_NO_DATA);
+ }
+
+ buf.ptr = cmd->data;
+ buf.size = cmd->lc;
+ buf.offset = 0;
+
+ return handleGetPublicKey(&buf, (bool) cmd->p1, flags);
+ case INS_GET_ADDRESS:
+ if (cmd->p1 > 1 || cmd->p2 > 0) {
+ return io_send_sw(ERR_WRONG_P1P2);
+ }
+ if (cmd->lc != sizeof(uint32_t) + sizeof(uint8_t)) {
+ return io_send_sw(ERR_WRONG_DATA_LENGTH);
+ }
+
+ if (!cmd->data) {
+ return io_send_sw(ERR_NO_DATA);
+ }
+
+ buf.ptr = cmd->data;
+ buf.size = cmd->lc;
+ buf.offset = 0;
+
+ return handleGetAddress(&buf, (bool) cmd->p1, flags);
+ case INS_SIGN:
+ if (cmd->p1 != 1 || cmd->p2 > 0) {
+ return io_send_sw(ERR_WRONG_P1P2);
+ }
+ if (cmd->lc == 0) {
+ return io_send_sw(ERR_WRONG_DATA_LENGTH);
+ }
+
+ buf.ptr = cmd->data;
+ buf.size = cmd->lc;
+ buf.offset = 0;
+
+ return handleSign(&buf, flags);
+
+ case INS_SIGN_TRANSACTION:
+ if (cmd->p1 != P1_CONFIRM || cmd->p2 > 3) {
+ return io_send_sw(ERR_WRONG_P1P2);
+ }
+
+ if (!cmd->data) {
+ return io_send_sw(ERR_NO_DATA);
+ }
+ // P2_MORE is a signal for more apdu to receive in current chunk;
+ // P2_EXTEND is a signal for extended buffer and can't be in first chunk;
+ // P2_MORE && !P2_EXTEND = first chunk;
+ // P2_EXTEND && !P2_MORE = last chunk;
+ // P2_EXTEND && P2_MORE = ordinary request without chunks;
+
+ // P2_EXTEND is set to signal that this APDU buffer extends, rather
+ // than replaces, the current message buffer
+ bool more = (bool) (cmd->p2 & P2_MORE);
+ bool first_data_chunk = !(cmd->p2 & P2_EXTEND);
+
+ buf.ptr = cmd->data;
+ buf.size = cmd->lc;
+ buf.offset = 0;
+
+ return handleSignTransaction(&buf, first_data_chunk, more, flags);
+ default:
+ return io_send_sw(ERR_INS_NOT_SUPPORTED);
+ }
+}
diff --git a/src/apdu/dispatcher.h b/src/apdu/dispatcher.h
new file mode 100644
index 0000000..34e0841
--- /dev/null
+++ b/src/apdu/dispatcher.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int apdu_dispatcher(const command_t* cmd, volatile unsigned int* flags);
diff --git a/src/apdu_constants.h b/src/apdu_constants.h
index cfefca3..d8f1160 100644
--- a/src/apdu_constants.h
+++ b/src/apdu_constants.h
@@ -1,5 +1,4 @@
-#ifndef _APDU_CONSTANTS_H_
-#define _APDU_CONSTANTS_H_
+#pragma once
#include
#include
@@ -9,24 +8,18 @@
#include "cx.h"
#include "os_io_seproxyhal.h"
-#define CLA 0xE0
+#define CLA 0xE0
#define INS_GET_APP_CONFIGURATION 0x01
-#define INS_GET_PUBLIC_KEY 0x02
-#define INS_SIGN 0x03
-#define INS_GET_ADDRESS 0x04
-#define INS_SIGN_TRANSACTION 0x05
+#define INS_GET_PUBLIC_KEY 0x02
+#define INS_SIGN 0x03
+#define INS_GET_ADDRESS 0x04
+#define INS_SIGN_TRANSACTION 0x05
-#define OFFSET_CLA 0
-#define OFFSET_INS 1
-#define OFFSET_P1 2
-#define OFFSET_P2 3
-#define OFFSET_LC 4
+#define OFFSET_CLA 0
+#define OFFSET_INS 1
+#define OFFSET_P1 2
+#define OFFSET_P2 3
+#define OFFSET_LC 4
#define OFFSET_CDATA 5
-void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx);
-void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx);
-void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx);
-void handleSign(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags);
-int handleSignTransaction(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, bool is_first_chunk, bool more);
-
-#endif
+#define APPVERSION_LEN 3
diff --git a/src/cell.c b/src/cell.c
index 5cd703f..c3595ec 100644
--- a/src/cell.c
+++ b/src/cell.c
@@ -62,18 +62,20 @@ uint16_t Cell_bit_len(struct Cell_t* self) {
return bit_len;
}
-uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const uint8_t cells_count) {
+uint16_t deserialize_cell(struct Cell_t* cell,
+ const uint8_t cell_index,
+ const uint8_t cells_count) {
uint8_t d1 = Cell_get_d1(cell);
- uint8_t level = d1 >> 5; // level
- uint8_t hashes = (d1 & 16) == 16; // with hashes
- uint8_t exotic = (d1 & 8) == 8; // exotic
- uint8_t rc = d1 & 7; // refs count
+ uint8_t level = d1 >> 5; // level
+ uint8_t hashes = (d1 & 16) == 16; // with hashes
+ uint8_t exotic = (d1 & 8) == 8; // exotic
+ uint8_t rc = d1 & 7; // refs count
uint8_t absent = rc == 7 && hashes;
uint8_t pruned = d1 == PRUNED_BRANCH_D1;
UNUSED(level);
VALIDATE(!hashes, ERR_INVALID_CELL);
- VALIDATE(!exotic || pruned, ERR_INVALID_CELL); // only ordinary or pruned cells are valid
+ VALIDATE(!exotic || pruned, ERR_INVALID_CELL); // only ordinary or pruned cells are valid
VALIDATE(rc <= MAX_REFERENCES_COUNT, ERR_INVALID_CELL);
VALIDATE(!absent, ERR_INVALID_CELL);
@@ -89,7 +91,7 @@ uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const u
VALIDATE(ref <= cells_count && ref > cell_index, ERR_INVALID_CELL);
}
- return CELL_DATA_OFFSET + data_size + refs_count; // cell size
+ return CELL_DATA_OFFSET + data_size + refs_count; // cell size
}
void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) {
@@ -108,7 +110,7 @@ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) {
return;
}
- uint8_t hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32))
+ uint8_t hash_buffer[266]; // d1(1) + d2(1) + data(128) + 4 * (depth(2) + hash(32))
uint16_t hash_buffer_offset = 0;
hash_buffer[0] = d1 & 0b00011111;
@@ -143,6 +145,9 @@ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index) {
hash_buffer_offset += HASH_SIZE;
}
- int result = cx_hash_sha256(hash_buffer, hash_buffer_offset, bc->hashes + cell_index * HASH_SIZE, HASH_SIZE);
+ int result = cx_hash_sha256(hash_buffer,
+ hash_buffer_offset,
+ bc->hashes + cell_index * HASH_SIZE,
+ HASH_SIZE);
VALIDATE(result == HASH_SIZE, ERR_INVALID_HASH);
}
diff --git a/src/cell.h b/src/cell.h
index 28fa859..f14105f 100644
--- a/src/cell.h
+++ b/src/cell.h
@@ -4,7 +4,7 @@
#include
#include
-#define CELL_DATA_OFFSET 2
+#define CELL_DATA_OFFSET 2
#define MAX_REFERENCES_COUNT 4
typedef struct Cell_t {
diff --git a/src/contract.c b/src/contract.c
index 45b353e..2b2acdf 100644
--- a/src/contract.c
+++ b/src/contract.c
@@ -7,117 +7,87 @@
#include "hashmap_label.h"
// Wallets code
-const uint8_t safe_multisig_wallet[] = { 0x01, 0x02, 0x49, 0x01,
- 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, 0x06,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF,
- 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
- 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 };
-
-const uint8_t safe_multisig_wallet_24h[] = { 0x01, 0x02, 0x49, 0x01,
- 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, 0x06,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF,
- 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
- 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 };
-
-const uint8_t setcode_multisig_wallet[] = { 0x01, 0x02, 0x65, 0x01,
- 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, 0x06,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF,
- 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
- 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 };
-
-const uint8_t bridge_multisig_wallet[] = { 0x01, 0x02, 0x45, 0x01,
- 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, 0x03,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20 };
-
-const uint8_t multisig_2_wallet[] = { 0x01, 0x02, 0x56, 0x01,
- 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, 0x03,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20 };
-
-const uint8_t multisig_2_1_wallet[] = { 0x01, 0x02, 0x4D, 0x01,
- 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, 0x03,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20 };
-
-const uint8_t surf_wallet[] = { 0x01, 0x02, 0x4D, 0x01,
- 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34, 0x03,
- 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x20 };
+const uint8_t safe_multisig_wallet[] = {
+ 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF4, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
+ 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
+
+const uint8_t safe_multisig_wallet_24h[] = {
+ 0x01, 0x02, 0x49, 0x01, 0x00, 0x10, 0xF7, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
+ 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
+
+const uint8_t setcode_multisig_wallet[] = {
+ 0x01, 0x02, 0x65, 0x01, 0x00, 0x1A, 0x04, 0x00, 0x02, 0x01, 0x34, 0x06, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x02, 0x03, 0xCF, 0x20, 0x05, 0x03, 0x01, 0x01, 0xDE, 0x04, 0x00,
+ 0x03, 0xD0, 0x20, 0x00, 0x41, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04};
+
+const uint8_t bridge_multisig_wallet[] = {
+ 0x01, 0x02, 0x45, 0x01, 0x00, 0x11, 0x04, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20};
+
+const uint8_t multisig_2_wallet[] = {
+ 0x01, 0x02, 0x56, 0x01, 0x00, 0x0F, 0xDD, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20};
+
+const uint8_t multisig_2_1_wallet[] = {
+ 0x01, 0x02, 0x4D, 0x01, 0x00, 0x10, 0xB2, 0x00, 0x02, 0x01, 0x34, 0x03, 0x01, 0x01,
+ 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20};
+
+const uint8_t surf_wallet[] = {0x01, 0x02, 0x4D, 0x01, 0x00, 0x12, 0xB4, 0x00, 0x02, 0x01, 0x34,
+ 0x03, 0x01, 0x01, 0x01, 0xC0, 0x02, 0x00, 0x43, 0xD0, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20};
// Wallets code hash
-const uint8_t wallet_v3_code_hash[] = { 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98,
- 0x77, 0x89, 0xBA, 0x23, 0x23, 0x58, 0x07, 0x2B,
- 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, 0x02, 0xA5,
- 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99 };
-
-const uint8_t ever_wallet_code_hash[] = { 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11,
- 0x81, 0x80, 0xAA, 0x3B, 0xD1, 0x0D, 0xD1, 0x9F,
- 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, 0xCF, 0x58,
- 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6 };
-
-const uint8_t safe_multisig_wallet_code_hash[] = { 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c,
- 0x9b, 0x39, 0x7b, 0x71, 0x71, 0x6f, 0x3f, 0xae,
- 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, 0xc5, 0x2e,
- 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05 };
-
-const uint8_t safe_multisig_wallet_24h_code_hash[] = { 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6,
- 0x2a, 0x4f, 0xf2, 0x91, 0xb1, 0x22, 0x8b, 0xf0,
- 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, 0x43, 0x6c,
- 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2 };
-
-const uint8_t setcode_multisig_wallet_code_hash[] = { 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce,
- 0xd7, 0xea, 0x8e, 0xde, 0x4b, 0xdf, 0x96, 0x34,
- 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, 0x06, 0x6f,
- 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08 };
-
-const uint8_t bridge_multisig_wallet_code_hash[] = { 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25,
- 0x9D, 0x7F, 0xA4, 0x84, 0x7B, 0x86, 0x33, 0x5B,
- 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, 0xBA, 0x4B,
- 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18 };
-
-const uint8_t multisig_2_wallet_code_hash[] = { 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05,
- 0xc5, 0xa1, 0xb8, 0xd8, 0xfd, 0x75, 0xcb, 0x72,
- 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, 0x53, 0x32,
- 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90 };
-
-const uint8_t multisig_2_1_wallet_code_hash[] = { 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1,
- 0x25, 0x3f, 0x34, 0x15, 0x82, 0x6c, 0x94, 0x6c,
- 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, 0x08, 0x62,
- 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3, };
-
-
-const uint8_t surf_wallet_code_hash[] = { 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1,
- 0xa2, 0xc1, 0x47, 0x93, 0x56, 0xf8, 0xf3, 0xee,
- 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, 0xf4, 0x78,
- 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82 };
+const uint8_t wallet_v3_code_hash[] = {
+ 0x84, 0xDA, 0xFA, 0x44, 0x9F, 0x98, 0xA6, 0x98, 0x77, 0x89, 0xBA, 0x23, 0x23, 0x58, 0x07, 0x2B,
+ 0xC0, 0xF7, 0x6D, 0xC4, 0x52, 0x40, 0x02, 0xA5, 0xD0, 0x91, 0x8B, 0x9A, 0x75, 0xD2, 0xD5, 0x99};
+
+const uint8_t ever_wallet_code_hash[] = {
+ 0x3B, 0xA6, 0x52, 0x8A, 0xB2, 0x69, 0x4C, 0x11, 0x81, 0x80, 0xAA, 0x3B, 0xD1, 0x0D, 0xD1, 0x9F,
+ 0xF4, 0x00, 0xB9, 0x09, 0xAB, 0x4D, 0xCF, 0x58, 0xFC, 0x69, 0x92, 0x5B, 0x2C, 0x7B, 0x12, 0xA6};
+
+const uint8_t safe_multisig_wallet_code_hash[] = {
+ 0x80, 0xd6, 0xc4, 0x7c, 0x4a, 0x25, 0x54, 0x3c, 0x9b, 0x39, 0x7b, 0x71, 0x71, 0x6f, 0x3f, 0xae,
+ 0x1e, 0x2c, 0x5d, 0x24, 0x71, 0x74, 0xc5, 0x2e, 0x2c, 0x19, 0xbd, 0x89, 0x64, 0x42, 0xb1, 0x05};
+
+const uint8_t safe_multisig_wallet_24h_code_hash[] = {
+ 0x7d, 0x09, 0x96, 0x94, 0x34, 0x06, 0xf7, 0xd6, 0x2a, 0x4f, 0xf2, 0x91, 0xb1, 0x22, 0x8b, 0xf0,
+ 0x6e, 0xbd, 0x3e, 0x04, 0x8b, 0x58, 0x43, 0x6c, 0x5b, 0x70, 0xfb, 0x77, 0xff, 0x8b, 0x4b, 0xf2};
+
+const uint8_t setcode_multisig_wallet_code_hash[] = {
+ 0xe2, 0xb6, 0x0b, 0x6b, 0x60, 0x2c, 0x10, 0xce, 0xd7, 0xea, 0x8e, 0xde, 0x4b, 0xdf, 0x96, 0x34,
+ 0x2c, 0x97, 0x57, 0x0a, 0x37, 0x98, 0x06, 0x6f, 0x3f, 0xb5, 0x0a, 0x4b, 0x2b, 0x27, 0xa2, 0x08};
+
+const uint8_t bridge_multisig_wallet_code_hash[] = {
+ 0xF3, 0xA0, 0x7A, 0xE8, 0x4F, 0xC3, 0x43, 0x25, 0x9D, 0x7F, 0xA4, 0x84, 0x7B, 0x86, 0x33, 0x5B,
+ 0x3F, 0xDC, 0xFC, 0x8B, 0x31, 0xF1, 0xBA, 0x4B, 0x7A, 0x94, 0x99, 0xD5, 0x53, 0x0F, 0x0B, 0x18};
+
+const uint8_t multisig_2_wallet_code_hash[] = {
+ 0x29, 0xb2, 0x47, 0x76, 0xb3, 0xdf, 0x6a, 0x05, 0xc5, 0xa1, 0xb8, 0xd8, 0xfd, 0x75, 0xcb, 0x72,
+ 0xa1, 0xd3, 0x3c, 0x0a, 0x44, 0x38, 0x53, 0x32, 0xa8, 0xbf, 0xc2, 0x72, 0x7f, 0xb6, 0x65, 0x90};
+
+const uint8_t multisig_2_1_wallet_code_hash[] = {
+ 0xd6, 0x6d, 0x19, 0x87, 0x66, 0xab, 0xdb, 0xe1, 0x25, 0x3f, 0x34, 0x15, 0x82, 0x6c, 0x94, 0x6c,
+ 0x37, 0x1f, 0x51, 0x12, 0x55, 0x24, 0x08, 0x62, 0x5a, 0xeb, 0x0b, 0x31, 0xe0, 0xef, 0x2d, 0xf3,
+};
+
+const uint8_t surf_wallet_code_hash[] = {
+ 0x20, 0x7d, 0xc5, 0x60, 0xc5, 0x95, 0x6d, 0xe1, 0xa2, 0xc1, 0x47, 0x93, 0x56, 0xf8, 0xf3, 0xee,
+ 0x70, 0xa5, 0x97, 0x67, 0xdb, 0x2b, 0xf4, 0x78, 0x8b, 0x1d, 0x61, 0xad, 0x42, 0xcd, 0xad, 0x82};
// Cell depths
const uint32_t safe_multisig_wallet_cell_depth = 0x0C;
@@ -139,7 +109,7 @@ void deserialize_cells_tree(struct ByteStream_t* src) {
VALIDATE(!index_included && !has_crc && !has_cache_bits, ERR_INVALID_CONTRACT);
}
- uint8_t ref_size = first_byte & 0x7; // size in bytes
+ uint8_t ref_size = first_byte & 0x7; // size in bytes
VALIDATE(ref_size == 1, ERR_INVALID_CONTRACT);
uint8_t offset_size = ByteStream_read_byte(src);
@@ -184,7 +154,7 @@ void deserialize_cells_tree(struct ByteStream_t* src) {
void find_public_key_cell() {
BocContext_t* bc = &boc_context;
- VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, ERR_INVALID_CONTRACT); // has data branch
+ VALIDATE(Cell_get_data(&bc->cells[0])[0] & 0x20, ERR_INVALID_CONTRACT); // has data branch
uint8_t refs_count = 0;
uint8_t* refs = Cell_get_refs(&bc->cells[0], &refs_count);
@@ -211,12 +181,12 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) {
// Compute data hash
{
- uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32)
+ uint8_t hash_buffer[42]; // d1(1) + d2(1) + data(8) + pubkey(32)
uint16_t hash_buffer_offset = 0;
- hash_buffer[0] = 0x00; // d1(1)
- hash_buffer[1] = 0x50; // d2(1)
+ hash_buffer[0] = 0x00; // d1(1)
+ hash_buffer[1] = 0x50; // d2(1)
hash_buffer_offset += 2;
// Data
@@ -225,7 +195,7 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) {
// Pubkey
uint8_t public_key[PUBLIC_KEY_LENGTH];
- get_public_key(account_number, public_key);
+ VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED);
memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH);
hash_buffer_offset += PUBLIC_KEY_LENGTH;
@@ -237,11 +207,11 @@ void compute_wallet_v3_address(uint32_t account_number, uint8_t* address) {
// Compute address
{
- uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32)
+ uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32)
uint16_t hash_buffer_offset = 0;
- hash_buffer[0] = 0x02; // d1(1)
- hash_buffer[1] = 0x01; // d2(1)
+ hash_buffer[0] = 0x02; // d1(1)
+ hash_buffer[1] = 0x01; // d2(1)
hash_buffer_offset += 2;
// Data
@@ -269,17 +239,17 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) {
// Compute data hash
{
- uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8)
+ uint8_t hash_buffer[42]; // d1(1) + d2(1) + pubkey(32) + data(8)
uint16_t hash_buffer_offset = 0;
- hash_buffer[0] = 0x00; // d1(1)
- hash_buffer[1] = 0x50; // d2(1)
+ hash_buffer[0] = 0x00; // d1(1)
+ hash_buffer[1] = 0x50; // d2(1)
hash_buffer_offset += 2;
// Pubkey
uint8_t public_key[PUBLIC_KEY_LENGTH];
- get_public_key(account_number, public_key);
+ VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED);
memcpy(hash_buffer + hash_buffer_offset, public_key, PUBLIC_KEY_LENGTH);
hash_buffer_offset += PUBLIC_KEY_LENGTH;
@@ -295,11 +265,11 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) {
// Compute address
{
- uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32)
+ uint8_t hash_buffer[71]; // d1(1) + d2(1) + data(5) + code_hash(32) + data_hash(32)
uint16_t hash_buffer_offset = 0;
- hash_buffer[0] = 0x02; // d1(1)
- hash_buffer[1] = 0x01; // d2(1)
+ hash_buffer[0] = 0x02; // d1(1)
+ hash_buffer[1] = 0x01; // d2(1)
hash_buffer_offset += 2;
// Data
@@ -310,7 +280,9 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) {
hash_buffer_offset += sizeof(uint32_t);
// Code hash
- memcpy(hash_buffer + hash_buffer_offset, ever_wallet_code_hash, sizeof(ever_wallet_code_hash));
+ memcpy(hash_buffer + hash_buffer_offset,
+ ever_wallet_code_hash,
+ sizeof(ever_wallet_code_hash));
hash_buffer_offset += sizeof(ever_wallet_code_hash);
// Data hash
@@ -322,17 +294,22 @@ void compute_ever_wallet_address(uint32_t account_number, uint8_t* address) {
}
}
-void compute_multisig_address(uint32_t account_number, const uint8_t* wallet, uint16_t wallet_size, const uint8_t* code_hash, uint32_t cell_depth, uint8_t* address) {
+void compute_multisig_address(uint32_t account_number,
+ const uint8_t* wallet,
+ uint16_t wallet_size,
+ const uint8_t* code_hash,
+ uint32_t cell_depth,
+ uint8_t* address) {
{
ByteStream_t src;
- ByteStream_init(&src, (uint8_t*)wallet, wallet_size);
+ ByteStream_init(&src, (uint8_t*) wallet, wallet_size);
deserialize_cells_tree(&src);
}
BocContext_t* bc = &boc_context;
VALIDATE(bc->cells_count != 0, ERR_INVALID_CONTRACT);
- find_public_key_cell(); // sets public key cell index to boc_context
+ find_public_key_cell(); // sets public key cell index to boc_context
// Set code hash
memcpy(bc->hashes + (bc->public_key_cell_index + 1) * HASH_SIZE, code_hash, HASH_SIZE);
@@ -341,12 +318,13 @@ void compute_multisig_address(uint32_t account_number, const uint8_t* wallet, ui
VALIDATE(bc->public_key_cell_index && bc->public_key_label_size_bits, ERR_INVALID_CONTRACT);
Cell_t* cell = &bc->cells[bc->public_key_cell_index];
uint8_t cell_data_size = Cell_get_data_size(cell);
- VALIDATE(cell_data_size != 0 && cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE, ERR_INVALID_CONTRACT);
+ VALIDATE(cell_data_size != 0 && cell_data_size <= MAX_PUBLIC_KEY_CELL_DATA_SIZE,
+ ERR_INVALID_CONTRACT);
uint8_t* cell_data = Cell_get_data(cell);
memcpy(bc->public_key_cell_data, cell_data, cell_data_size);
uint8_t* public_key = data_context.pk_context.public_key;
- get_public_key(account_number, public_key);
+ VALIDATE(get_public_key(account_number, public_key) == 0, ERR_GET_PUBLIC_KEY_FAILED);
uint8_t* data = bc->public_key_cell_data;
SliceData_t slice;
@@ -442,6 +420,7 @@ void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* ad
#else
-void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* address) {}
+void get_address(const uint32_t account_number, uint8_t wallet_type, uint8_t* address) {
+}
#endif
diff --git a/src/contract.h b/src/contract.h
index 80b8d2e..2f0be49 100644
--- a/src/contract.h
+++ b/src/contract.h
@@ -6,27 +6,27 @@
#include
#include
-#define SIGN_TRANSACTION_FLOW_ERROR -1
+#define SIGN_TRANSACTION_FLOW_ERROR -1
#define SIGN_TRANSACTION_FLOW_TRANSFER 0
-#define SIGN_TRANSACTION_FLOW_DEPLOY 1
-#define SIGN_TRANSACTION_FLOW_CONFIRM 2
-#define SIGN_TRANSACTION_FLOW_BURN 3
+#define SIGN_TRANSACTION_FLOW_DEPLOY 1
+#define SIGN_TRANSACTION_FLOW_CONFIRM 2
+#define SIGN_TRANSACTION_FLOW_BURN 3
enum {
- WALLET_V3 = 0,
- EVER_WALLET = 1,
- SAFE_MULTISIG_WALLET = 2,
- SAFE_MULTISIG_WALLET_24H = 3,
- SETCODE_MULTISIG_WALLET = 4,
- BRIDGE_MULTISIG_WALLET = 5,
- SURF_WALLET = 6,
- MULTISIG_2 = 7,
- MULTISIG_2_1 = 8,
+ WALLET_V3 = 0,
+ EVER_WALLET = 1,
+ SAFE_MULTISIG_WALLET = 2,
+ SAFE_MULTISIG_WALLET_24H = 3,
+ SETCODE_MULTISIG_WALLET = 4,
+ BRIDGE_MULTISIG_WALLET = 5,
+ SURF_WALLET = 6,
+ MULTISIG_2 = 7,
+ MULTISIG_2_1 = 8,
};
enum {
MULTISIG_DEPLOY_TRANSACTION = 1813932348,
- MULTISIG_SEND_TRANSACTION = 1290691692,
+ MULTISIG_SEND_TRANSACTION = 1290691692,
MULTISIG_SUBMIT_TRANSACTION = 320701133,
MULTISIG_CONFIRM_TRANSACTION = 447168749,
@@ -40,11 +40,7 @@ enum {
TOKEN_TRANSFER_TO_WALLET = 1185535980, // Ordinary transfer
};
-enum {
- NORMAL_FLAG = 3,
- ALL_BALANCE_FLAG = 128,
- ALL_BALANCE_AND_DELETE_FLAG = 160
-};
+enum { NORMAL_FLAG = 3, ALL_BALANCE_FLAG = 128, ALL_BALANCE_AND_DELETE_FLAG = 160 };
struct ByteStream_t;
void deserialize_cells_tree(struct ByteStream_t* src);
diff --git a/src/errors.h b/src/errors.h
index b6b5ef9..06c5bd2 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -23,6 +23,17 @@ enum {
ERR_INVALID_CELL = 0x6B17,
ERR_INVALID_CONTRACT = 0x6B18,
ERR_INVALID_MESSAGE = 0x6B19,
+ ERR_SIGNING_FAILED = 0x6B20,
+ ERR_GENERATE_PAIR_FAILED = 0x6B21,
+ ERR_INIT_PRIVATE_KEY_FAILED = 0x6B22,
+ ERR_DERIVE_PATH_FAILED = 0x6B23,
+ ERR_WRONG_DATA_LENGTH = 0x6B24,
+ ERR_CLA_NOT_SUPPORTED = 0x6B25,
+ ERR_WRONG_P1P2 = 0x6B26,
+ ERR_INS_NOT_SUPPORTED = 0x6B27,
+ ERR_NO_DATA = 0x6B28,
+ ERR_GET_PUBLIC_KEY_FAILED = 0x6B29,
+ ERR_USER_REJECTED = 0x6985,
};
#endif
diff --git a/src/get_address.c b/src/get_address.c
deleted file mode 100644
index cef6b3c..0000000
--- a/src/get_address.c
+++ /dev/null
@@ -1,81 +0,0 @@
-#include "apdu_constants.h"
-#include "globals.h"
-#include "utils.h"
-#include "contract.h"
-#include "slice_data.h"
-#include "byte_stream.h"
-
-static uint8_t set_result_get_address() {
- uint8_t tx = 0;
- G_io_apdu_buffer[tx++] = ADDRESS_LENGTH;
- memmove(G_io_apdu_buffer + tx, data_context.addr_context.address, ADDRESS_LENGTH);
- tx += ADDRESS_LENGTH;
- reset_app_context();
- return tx;
-}
-
-UX_STEP_NOCB(
- ux_display_address_flow_1_step,
- pnn,
- {
- &C_icon_eye,
- "Verify",
- "address",
- });
-UX_STEP_NOCB(
- ux_display_address_flow_2_step,
- bnnn_paging,
- {
- .title = "Address",
- .text = data_context.addr_context.address_str,
- });
-UX_STEP_CB(
- ux_display_address_flow_3_step,
- pb,
- send_response(0, false),
- {
- &C_icon_crossmark,
- "Reject",
- });
-UX_STEP_CB(
- ux_display_address_flow_4_step,
- pb,
- send_response(set_result_get_address(), true),
- {
- &C_icon_validate_14,
- "Approve",
- });
-
-UX_FLOW(ux_display_address_flow,
- &ux_display_address_flow_1_step,
- &ux_display_address_flow_2_step,
- &ux_display_address_flow_3_step,
- &ux_display_address_flow_4_step
-);
-
-void handleGetAddress(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) {
- VALIDATE(p2 == 0 && dataLength == (sizeof(uint32_t) + sizeof(uint8_t)), ERR_INVALID_REQUEST);
-
- size_t offset = 0;
-
- uint32_t account_number = readUint32BE(dataBuffer + offset);
- offset += sizeof(account_number);
-
- uint8_t wallet_type = dataBuffer[offset];
-
- get_address(account_number, wallet_type, data_context.addr_context.address);
-
- if (p1 == P1_NON_CONFIRM) {
- *tx = set_result_get_address();
- THROW(SUCCESS);
- }
- if (p1 == P1_CONFIRM) {
- AddressContext_t* context = &data_context.addr_context;
- format_hex(context->address, sizeof(context->address), context->address_str, sizeof(context->address_str));
- ux_flow_init(0, ux_display_address_flow, NULL);
- *flags |= IO_ASYNCH_REPLY;
- return;
- }
-
- THROW(ERR_INVALID_REQUEST);
-}
diff --git a/src/get_app_configuration.c b/src/get_app_configuration.c
deleted file mode 100644
index d45dd60..0000000
--- a/src/get_app_configuration.c
+++ /dev/null
@@ -1,15 +0,0 @@
-#include "apdu_constants.h"
-#include "utils.h"
-#include "errors.h"
-
-void handleGetAppConfiguration(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) {
- UNUSED(dataBuffer);
- UNUSED(flags);
- VALIDATE(p1 == 0 && p2 == 0 && dataLength == 0, ERR_INVALID_REQUEST);
-
- G_io_apdu_buffer[0] = LEDGER_MAJOR_VERSION;
- G_io_apdu_buffer[1] = LEDGER_MINOR_VERSION;
- G_io_apdu_buffer[2] = LEDGER_PATCH_VERSION;
- *tx = 3;
- THROW(SUCCESS);
-}
diff --git a/src/get_public_key.c b/src/get_public_key.c
deleted file mode 100644
index 1617136..0000000
--- a/src/get_public_key.c
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "os.h"
-#include "ux.h"
-#include "utils.h"
-#include "apdu_constants.h"
-#include "errors.h"
-
-static uint8_t set_result_get_public_key() {
- uint8_t tx = 0;
- G_io_apdu_buffer[tx++] = PUBLIC_KEY_LENGTH;
- memmove(G_io_apdu_buffer + tx, data_context.pk_context.public_key, PUBLIC_KEY_LENGTH);
- tx += PUBLIC_KEY_LENGTH;
- reset_app_context();
- return tx;
-}
-
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-
-UX_STEP_NOCB(
- ux_display_public_flow_1_step,
- bnnn_paging,
- {
- .title = "Public key",
- .text = data_context.pk_context.public_key_str,
- });
-UX_STEP_CB(
- ux_display_public_flow_2_step,
- pb,
- send_response(0, false),
- {
- &C_icon_crossmark,
- "Reject",
- });
-UX_STEP_CB(
- ux_display_public_flow_3_step,
- pb,
- send_response(set_result_get_public_key(), true),
- {
- &C_icon_validate_14,
- "Approve",
- });
-
-UX_FLOW(ux_display_public_flow,
- &ux_display_public_flow_1_step,
- &ux_display_public_flow_2_step,
- &ux_display_public_flow_3_step
-);
-
-#endif
-
-void handleGetPublicKey(uint8_t p1, uint8_t p2, uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, volatile unsigned int *tx) {
- VALIDATE(p2 == 0 && dataLength == sizeof(uint32_t), ERR_INVALID_REQUEST);
-
- uint32_t account_number = readUint32BE(dataBuffer);
- PublicKeyContext_t* context = &data_context.pk_context;
- get_public_key(account_number, context->public_key);
- if (p1 == P1_NON_CONFIRM) {
- *tx = set_result_get_public_key();
- THROW(SUCCESS);
- }
-
- if (p1 == P1_CONFIRM) {
- format_hex(context->public_key, sizeof(context->public_key), context->public_key_str, sizeof(context->public_key_str));
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
- ux_flow_init(0, ux_display_public_flow, NULL);
-#endif
- *flags |= IO_ASYNCH_REPLY;
- return;
- }
-
- THROW(ERR_INVALID_REQUEST);
-}
diff --git a/src/globals.c b/src/globals.c
deleted file mode 100644
index e8d7cc0..0000000
--- a/src/globals.c
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "globals.h"
-#include "os.h"
-#include "ux.h"
-
-ux_state_t G_ux;
-bolos_ux_params_t G_ux_params;
-
-// display stepped screens
-unsigned int ux_step;
-unsigned int ux_step_count;
diff --git a/src/globals.h b/src/globals.h
index ae82278..58338bb 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -8,40 +8,40 @@
#include "errors.h"
#include "cell.h"
-#define P1_CONFIRM 0x01
+#define P1_CONFIRM 0x01
#define P1_NON_CONFIRM 0x00
#define P2_EXTEND 0x01
-#define P2_MORE 0x02
+#define P2_MORE 0x02
-#define PUBLIC_KEY_LENGTH 32
-#define ADDRESS_LENGTH 32
+#define PUBLIC_KEY_LENGTH 32
+#define ADDRESS_LENGTH 32
#define TRANSACTION_ID_LENGTH 8
-#define BIP32_PATH 5
-#define AMOUNT_LENGHT 16
-#define TO_SIGN_LENGTH 32
-#define SIGN_MAGIC_LENGTH 4
-#define CHAIN_ID_LENGTH 4
-#define SIGNATURE_LENGTH 64
-#define HASH_SIZE 32
-#define MAX_ROOTS_COUNT 1
-
-#define PRUNED_BRANCH_D1 0b00101000
+#define BIP32_PATH 5
+#define AMOUNT_LENGHT 16
+#define TO_SIGN_LENGTH 32
+#define SIGN_MAGIC_LENGTH 4
+#define CHAIN_ID_LENGTH 4
+#define SIGNATURE_LENGTH 64
+#define HASH_SIZE 32
+#define MAX_ROOTS_COUNT 1
+
+#define PRUNED_BRANCH_D1 0b00101000
#define PRUNED_BRANCH_DATA_SIZE 36
#define MAX_TICKER_LEN 10
-#define MAX_DATA_LEN 1024
+#define MAX_DATA_LEN 1024
#define WALLET_ID 0x4BA92D8A
-#define MAX_CONTRACT_CELLS_COUNT 7
-#define HASHES_BUFFER_SIZE (MAX_CONTRACT_CELLS_COUNT * HASH_SIZE)
-#define MAX_PUBLIC_KEY_CELL_DATA_SIZE 36 // label(3) + public key(32) + tag(1)
+#define MAX_CONTRACT_CELLS_COUNT 16
+#define HASHES_BUFFER_SIZE (MAX_CONTRACT_CELLS_COUNT * HASH_SIZE)
+#define MAX_PUBLIC_KEY_CELL_DATA_SIZE 36 // label(3) + public key(32) + tag(1)
-#define FLAG_WITH_WALLET_ID 0x01
+#define FLAG_WITH_WALLET_ID 0x01
#define FLAG_WITH_WORKCHAIN_ID 0x02
-#define FLAG_WITH_ADDRESS 0x04
-#define FLAG_WITH_CHAIN_ID 0x08
+#define FLAG_WITH_ADDRESS 0x04
+#define FLAG_WITH_CHAIN_ID 0x08
void reset_app_context(void);
diff --git a/src/handler/get_address.c b/src/handler/get_address.c
new file mode 100644
index 0000000..463269c
--- /dev/null
+++ b/src/handler/get_address.c
@@ -0,0 +1,33 @@
+#include "format.h"
+#include "read.h"
+#include "apdu_constants.h"
+#include "globals.h"
+#include "utils.h"
+#include "contract.h"
+#include "slice_data.h"
+#include "byte_stream.h"
+#include "ui/display.h"
+#include "errors.h"
+#include "io.h"
+#include "helper/send_response.h"
+
+int handleGetAddress(buffer_t* cdata, bool display, volatile unsigned int* flags) {
+ uint32_t account_number = read_u32_be(cdata->ptr, cdata->offset);
+ cdata->offset += sizeof(account_number);
+
+ uint8_t wallet_type = cdata->ptr[cdata->offset++];
+
+ AddressContext_t* context = &data_context.addr_context;
+ get_address(account_number, wallet_type, context->address);
+
+ if (display) {
+ format_hex(context->address,
+ sizeof(context->address),
+ context->address_str,
+ sizeof(context->address_str));
+ ui_display_address();
+ *flags |= IO_ASYNCH_REPLY;
+ return 0;
+ }
+ return helper_send_response_address();
+}
diff --git a/src/handler/get_address.h b/src/handler/get_address.h
new file mode 100644
index 0000000..74dbf4e
--- /dev/null
+++ b/src/handler/get_address.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include
+
+/**
+ * Handles the get address command
+ * @param cdata command data
+ * @param display display flag
+ * @param flags flags
+ * @return 0 on success, error code on failure
+ */
+int handleGetAddress(buffer_t* cdata, bool display, volatile unsigned int* flags);
diff --git a/src/handler/get_app_configuration.c b/src/handler/get_app_configuration.c
new file mode 100644
index 0000000..600a3dd
--- /dev/null
+++ b/src/handler/get_app_configuration.c
@@ -0,0 +1,26 @@
+
+#include // uint*_t
+#include // UINT8_MAX
+#include // _Static_assert
+
+#include "apdu_constants.h"
+#include "utils.h"
+#include "errors.h"
+#include "io.h"
+
+int handleGetAppConfiguration() {
+ _Static_assert(APPVERSION_LEN == 3, "Length of (MAJOR || MINOR || PATCH) must be 3!");
+ _Static_assert(MAJOR_VERSION >= 0 && MAJOR_VERSION <= UINT8_MAX,
+ "MAJOR version must be between 0 and 255!");
+ _Static_assert(MINOR_VERSION >= 0 && MINOR_VERSION <= UINT8_MAX,
+ "MINOR version must be between 0 and 255!");
+ _Static_assert(PATCH_VERSION >= 0 && PATCH_VERSION <= UINT8_MAX,
+ "PATCH version must be between 0 and 255!");
+
+ return io_send_response_pointer(
+ (const uint8_t*) &(uint8_t[APPVERSION_LEN]){(uint8_t) MAJOR_VERSION,
+ (uint8_t) MINOR_VERSION,
+ (uint8_t) PATCH_VERSION},
+ APPVERSION_LEN,
+ SUCCESS);
+}
diff --git a/src/handler/get_app_configuration.h b/src/handler/get_app_configuration.h
new file mode 100644
index 0000000..48b05a5
--- /dev/null
+++ b/src/handler/get_app_configuration.h
@@ -0,0 +1,3 @@
+#pragma once
+
+int handleGetAppConfiguration();
diff --git a/src/handler/get_public_key.c b/src/handler/get_public_key.c
new file mode 100644
index 0000000..a4c47d1
--- /dev/null
+++ b/src/handler/get_public_key.c
@@ -0,0 +1,30 @@
+#include "os.h"
+#include "ux.h"
+#include "format.h"
+#include "read.h"
+#include "buffer.h"
+#include "parser.h"
+#include "utils.h"
+#include "apdu_constants.h"
+#include "errors.h"
+#include "ui/display.h"
+#include "helper/send_response.h"
+
+int handleGetPublicKey(buffer_t* cdata, bool display, volatile unsigned int* flags) {
+ uint32_t account_number = read_u32_be(cdata->ptr, cdata->offset);
+ PublicKeyContext_t* context = &data_context.pk_context;
+ if (get_public_key(account_number, context->public_key) != 0) {
+ return io_send_sw(ERR_GET_PUBLIC_KEY_FAILED);
+ }
+
+ if (display) {
+ format_hex(context->public_key,
+ sizeof(context->public_key),
+ context->public_key_str,
+ sizeof(context->public_key_str));
+ ui_display_public_key();
+ *flags |= IO_ASYNCH_REPLY;
+ return 0;
+ }
+ return helper_send_response_public_key();
+}
diff --git a/src/handler/get_public_key.h b/src/handler/get_public_key.h
new file mode 100644
index 0000000..1cb0bb0
--- /dev/null
+++ b/src/handler/get_public_key.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include
+
+/**
+ * Handles the get public key command
+ * @param cdata command data
+ * @param display display flag
+ * @param flags flags
+ */
+int handleGetPublicKey(buffer_t* cdata, bool display, volatile unsigned int* flags);
diff --git a/src/handler/sign.c b/src/handler/sign.c
new file mode 100644
index 0000000..8ccf25e
--- /dev/null
+++ b/src/handler/sign.c
@@ -0,0 +1,30 @@
+#include "format.h"
+#include "read.h"
+#include "buffer.h"
+#include "apdu_constants.h"
+#include "utils.h"
+#include "errors.h"
+#include "ui/display.h"
+#include "helper/send_response.h"
+
+static const char SIGN_MAGIC[] = {0xFF, 0xFF, 0xFF, 0xFF};
+
+int handleSign(buffer_t* cdata, volatile unsigned int* flags) {
+ SignContext_t* context = &data_context.sign_context;
+
+ VALIDATE(cdata->size >= sizeof(context->account_number), ERR_INVALID_REQUEST);
+ context->account_number = read_u32_be(cdata->ptr, cdata->offset);
+ cdata->offset += sizeof(context->account_number);
+
+ VALIDATE(cdata->size >= cdata->offset + TO_SIGN_LENGTH, ERR_INVALID_REQUEST);
+ memcpy(context->to_sign, SIGN_MAGIC, SIGN_MAGIC_LENGTH);
+ memcpy(context->to_sign + SIGN_MAGIC_LENGTH, cdata->ptr + cdata->offset, TO_SIGN_LENGTH);
+ format_hex(context->to_sign,
+ SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH,
+ context->to_sign_str,
+ sizeof(context->to_sign_str));
+
+ ui_display_sign();
+ *flags |= IO_ASYNCH_REPLY;
+ return 0;
+}
diff --git a/src/handler/sign.h b/src/handler/sign.h
new file mode 100644
index 0000000..79a13ae
--- /dev/null
+++ b/src/handler/sign.h
@@ -0,0 +1,10 @@
+#pragma once
+
+#include
+#include "buffer.h"
+/**
+ * Handles the sign command
+ * @param cdata input data buffer
+ * @param flags pointer to flags
+ */
+int handleSign(buffer_t* cdata, volatile unsigned int* flags);
diff --git a/src/handler/sign_transaction.c b/src/handler/sign_transaction.c
new file mode 100644
index 0000000..2a3acdf
--- /dev/null
+++ b/src/handler/sign_transaction.c
@@ -0,0 +1,121 @@
+#include "apdu_constants.h"
+#include "buffer.h"
+#include "read.h"
+#include "utils.h"
+#include "io.h"
+#include "errors.h"
+#include "byte_stream.h"
+#include "message.h"
+#include "contract.h"
+#include "ui/display.h"
+
+int handleSignTransaction(buffer_t* cdata,
+ bool is_first_chunk,
+ bool more,
+ volatile unsigned int* flags) {
+ if (is_first_chunk) {
+ reset_app_context();
+ }
+
+ SignTransactionContext_t* context = &data_context.sign_tr_context;
+
+ if (is_first_chunk) {
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->account_number),
+ ERR_INVALID_REQUEST);
+ context->account_number = read_u32_be(cdata->ptr, cdata->offset);
+ cdata->offset += sizeof(context->account_number);
+
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->origin_wallet_type),
+ ERR_INVALID_REQUEST);
+ context->origin_wallet_type = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(context->origin_wallet_type);
+
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->decimals), ERR_INVALID_REQUEST);
+ context->decimals = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(context->decimals);
+
+ VALIDATE(cdata->size >= cdata->offset + sizeof(uint8_t), ERR_INVALID_REQUEST);
+ uint8_t ticker_len = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(ticker_len);
+
+ VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH);
+
+ VALIDATE(cdata->size >= cdata->offset + ticker_len, ERR_INVALID_REQUEST);
+ memcpy(context->ticker, cdata->ptr + cdata->offset, ticker_len);
+ cdata->offset += ticker_len;
+
+ VALIDATE(cdata->size >= cdata->offset + sizeof(uint8_t), ERR_INVALID_REQUEST);
+ uint8_t metadata = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(metadata);
+
+ // Read wallet type if present
+ if (metadata & FLAG_WITH_WALLET_ID) {
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->current_wallet_type),
+ ERR_INVALID_REQUEST);
+ context->current_wallet_type = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(context->current_wallet_type);
+ } else {
+ context->current_wallet_type = context->origin_wallet_type;
+ }
+
+ // Get address
+ get_address(context->account_number, context->origin_wallet_type, context->address);
+ memset(&boc_context, 0, sizeof(boc_context));
+
+ // Read wc if present
+ context->wc = DEFAULT_WORKCHAIN_ID;
+ if (metadata & FLAG_WITH_WORKCHAIN_ID) {
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->wc), ERR_INVALID_REQUEST);
+ context->wc = cdata->ptr[cdata->offset];
+ cdata->offset += sizeof(context->wc);
+ }
+
+ // Read initial address if present
+ if (metadata & FLAG_WITH_ADDRESS) {
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->address), ERR_INVALID_REQUEST);
+ memcpy(context->prepend_address, cdata->ptr + cdata->offset, ADDRESS_LENGTH);
+ cdata->offset += sizeof(context->address);
+ } else {
+ memcpy(context->prepend_address, context->address, ADDRESS_LENGTH);
+ }
+
+ // Read chain id if present
+ if (metadata & FLAG_WITH_CHAIN_ID) {
+ context->sign_with_chain_id = true;
+
+ VALIDATE(cdata->size >= cdata->offset + sizeof(context->chain_id), ERR_INVALID_REQUEST);
+ memcpy(context->chain_id, cdata->ptr + cdata->offset, CHAIN_ID_LENGTH);
+ cdata->offset += sizeof(context->chain_id);
+ } else {
+ context->sign_with_chain_id = false;
+ }
+ }
+ // cdata->offset is a pointer to cdata->ptr, or the number of bytes we moved. here +
+ // cdata->offset means start of the message we need to save data to a context buffer and add
+ // msg_length to cdata->offset of this buffer
+ uint8_t* msg_begin = (uint8_t*) (cdata->ptr + cdata->offset);
+
+ // Since we check LC cdata->size can not be manipulated
+ uint16_t msg_length = cdata->size - cdata->offset;
+
+ if (msg_begin && msg_length > 0) { // if data exists
+ VALIDATE(context->data_offset + msg_length < sizeof(context->data), ERR_INVALID_DATA);
+ memcpy(context->data + context->data_offset, msg_begin, msg_length);
+ context->data_offset += msg_length; // add length of the new message to our context offset
+ }
+
+ if (more) {
+ return io_send_sw(SUCCESS);
+ }
+
+ // Handle transaction
+ ByteStream_t src;
+ ByteStream_init(&src, context->data, context->data_offset);
+
+ int flow = prepare_to_sign(&src, context->wc, context->address, context->prepend_address);
+
+ ui_display_sign_transaction(flow);
+
+ *flags |= IO_ASYNCH_REPLY;
+ return 0;
+}
diff --git a/src/handler/sign_transaction.h b/src/handler/sign_transaction.h
new file mode 100644
index 0000000..635cb6b
--- /dev/null
+++ b/src/handler/sign_transaction.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+#include
+
+/**
+ * Handles the sign transaction command
+ * @param cdata input data buffer
+ * @param is_first_chunk indicates if this is the first chunk of data
+ * @param more indicates if more chunks are expected
+ * @param flags pointer to flags
+ * @return 0 on success, -1 on error
+ */
+int handleSignTransaction(buffer_t* cdata,
+ bool is_first_chunk,
+ bool more,
+ volatile unsigned int* flags);
diff --git a/src/hashmap_label.c b/src/hashmap_label.c
index 84e5fe2..aaf85a5 100644
--- a/src/hashmap_label.c
+++ b/src/hashmap_label.c
@@ -10,15 +10,15 @@ uint8_t get_label_same(uint8_t max, struct SliceData_t* slice, struct SliceData_
VALIDATE(length <= 64, ERR_RANGE_CHECK);
uint8_t length_bytes = length / 8 + (length % 8 ? 1 : 0);
- SliceData_fill(label, value, length_bytes);
+ SliceData_fill(label, value, length_bytes);
SliceData_truncate(label, length);
return length >= max ? 0 : (max - length);
}
uint8_t get_label(uint8_t max, struct SliceData_t* slice, struct SliceData_t* label) {
VALIDATE(SliceData_is_empty(slice) == false, ERR_SLICE_IS_EMPTY);
- VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short
- VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long
+ VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label short
+ VALIDATE(SliceData_get_next_bit(slice) == 1, ERR_WRONG_LABEL); // label long
return get_label_same(max, slice, label);
}
@@ -43,7 +43,7 @@ void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t* key)
if (SliceData_equal(&label, key)) {
uint8_t len = 16 - leading_zeros(bit_len);
- uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len
+ uint8_t label_size_bits = 2 + 1 + len; // prefix + key bit + len
boc_context.public_key_label_size_bits = label_size_bits;
boc_context.public_key_cell_index = cell_index;
return;
@@ -51,10 +51,12 @@ void put_to_node(uint8_t cell_index, uint16_t bit_len, struct SliceData_t* key)
// common prefix
{
- uint8_t max_prefix_len = MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key));
+ uint8_t max_prefix_len =
+ MIN(SliceData_remaining_bits(&label), SliceData_remaining_bits(key));
VALIDATE(max_prefix_len <= 64, ERR_RANGE_CHECK);
uint8_t i = 0;
- while (i < max_prefix_len && SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) {
+ while (i < max_prefix_len &&
+ SliceData_get_bits(&label, i, 1) == SliceData_get_bits(key, i, 1)) {
i += 1;
}
diff --git a/src/helper/send_response.c b/src/helper/send_response.c
new file mode 100644
index 0000000..a5a211f
--- /dev/null
+++ b/src/helper/send_response.c
@@ -0,0 +1,39 @@
+#include "helper/send_response.h"
+
+int helper_send_response_public_key() {
+ uint8_t resp[1 + PUBLIC_KEY_LENGTH] = {0};
+ size_t offset = 0;
+ resp[offset++] = PUBLIC_KEY_LENGTH;
+ memmove(resp + offset, data_context.pk_context.public_key, PUBLIC_KEY_LENGTH);
+ offset += PUBLIC_KEY_LENGTH;
+ reset_app_context();
+ return io_send_response_pointer(resp, offset, SUCCESS);
+}
+
+int helper_send_response_address() {
+ uint8_t resp[1 + ADDRESS_LENGTH] = {0};
+ size_t offset = 0;
+ resp[offset++] = ADDRESS_LENGTH;
+ memmove(resp + offset, data_context.addr_context.address, ADDRESS_LENGTH);
+ offset += ADDRESS_LENGTH;
+ reset_app_context();
+ return io_send_response_pointer(resp, offset, SUCCESS);
+}
+
+int helper_send_response_sign() {
+ uint8_t resp[1 + SIGNATURE_LENGTH] = {0};
+ size_t offset = 0;
+ resp[offset++] = SIGNATURE_LENGTH;
+ memmove(resp + offset, data_context.sign_context.signature, SIGNATURE_LENGTH);
+ offset += SIGNATURE_LENGTH;
+ return io_send_response_pointer(resp, offset, SUCCESS);
+}
+
+int helper_send_response_sign_transaction() {
+ uint8_t resp[1 + SIGNATURE_LENGTH] = {0};
+ size_t offset = 0;
+ resp[offset++] = SIGNATURE_LENGTH;
+ memmove(resp + offset, data_context.sign_tr_context.signature, SIGNATURE_LENGTH);
+ offset += SIGNATURE_LENGTH;
+ return io_send_response_pointer(resp, offset, SUCCESS);
+}
diff --git a/src/helper/send_response.h b/src/helper/send_response.h
new file mode 100644
index 0000000..5ca7d0a
--- /dev/null
+++ b/src/helper/send_response.h
@@ -0,0 +1,9 @@
+#pragma once
+#include "globals.h"
+#include "utils.h"
+#include "io.h"
+
+int helper_send_response_public_key();
+int helper_send_response_address();
+int helper_send_response_sign_transaction();
+int helper_send_response_sign();
diff --git a/src/main.c b/src/main.c
index 040ca7f..7789413 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,25 +1,27 @@
/*******************************************************************************
-* Ledger Free TON App
-* (c) 2016 Ledger
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-********************************************************************************/
+ * Ledger Free TON App
+ * (c) 2016 Ledger
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ********************************************************************************/
#include "utils.h"
-#include "menu.h"
+#include "io.h"
#include "apdu_constants.h"
-
-unsigned char G_io_seproxyhal_spi_buffer[IO_SEPROXYHAL_BUFFER_SIZE_B];
+#include "parser.h"
+#include "errors.h"
+#include "ui/menu.h"
+#include "apdu/dispatcher.h"
BocContext_t boc_context;
DataContext_t data_context;
@@ -29,352 +31,56 @@ void reset_app_context() {
memset(&data_context, 0, sizeof(data_context));
}
-void reset_spi_buffer() {
- memset(&G_io_seproxyhal_spi_buffer, 0, sizeof(G_io_seproxyhal_spi_buffer));
-}
-
-void handleApdu(volatile unsigned int *flags, volatile unsigned int *tx, int rx) {
- unsigned short sw = 0;
-
- if (!flags || !tx) {
- THROW(0x6802);
- }
-
- if (rx < 0) {
- THROW(0x6813);
- }
-
- BEGIN_TRY {
- TRY {
- if (G_io_apdu_buffer[OFFSET_CLA] != CLA) {
- THROW(0x6E00);
- }
- // must at least hold the class and instruction
- if (rx <= OFFSET_INS) {
- THROW(0x6b00);
- }
- PRINTF("command: %d\n", G_io_apdu_buffer[OFFSET_INS]);
- switch (G_io_apdu_buffer[OFFSET_INS]) {
- case INS_GET_APP_CONFIGURATION: {
- if (G_io_apdu_buffer[OFFSET_P1] != 0 || G_io_apdu_buffer[OFFSET_P2] != 0) {
- THROW(0x6802);
- }
-
- handleGetAppConfiguration(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2],
- G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx);
- } break;
-
- case INS_GET_PUBLIC_KEY: {
- if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) {
- // the length of the APDU should match what's in the 5-byte header.
- // If not fail. Don't want to buffer overrun or anything.
- THROW(0x6985);
- }
-
- handleGetPublicKey(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx);
- } break;
-
- case INS_GET_ADDRESS: {
- if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) {
- // the length of the APDU should match what's in the 5-byte header.
- // If not fail. Don't want to buffer overrun or anything.
- THROW(0x6985);
- }
-
- handleGetAddress(G_io_apdu_buffer[OFFSET_P1], G_io_apdu_buffer[OFFSET_P2], G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, tx);
- } break;
-
- case INS_SIGN: {
- if (G_io_apdu_buffer[OFFSET_P1] != P1_CONFIRM || G_io_apdu_buffer[OFFSET_P2] != 0) {
- THROW(0x6802);
- }
-
- if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) {
- // the length of the APDU should match what's in the 5-byte header.
- // If not fail. Don't want to buffer overrun or anything.
- THROW(0x6985);
- }
-
- handleSign(G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags);
- } break;
-
- case INS_SIGN_TRANSACTION: {
- if (G_io_apdu_buffer[OFFSET_LC] != rx - OFFSET_CDATA) {
- // the length of the APDU should match what's in the 5-byte header.
- // If not fail. Don't want to buffer overrun or anything.
- THROW(0x6985);
- }
-
- uint8_t p1 = G_io_apdu_buffer[OFFSET_P1];
- if (p1 == P1_NON_CONFIRM) {
- // Don't allow blind signing.
- THROW(0x6808);
- }
-
- uint8_t p2 = G_io_apdu_buffer[OFFSET_P2];
- bool more = (bool) (p2 & P2_MORE);
-
- // P2_MORE is a signal for more apdu to receive in current chunk;
- // P2_EXTEND is a signal for extended buffer and can't be in first chunk;
- // P2_MORE && !P2_EXTEND = first chunk;
- // P2_EXTEND && !P2_MORE = last chunk;
- // P2_EXTEND && P2_MORE = ordinary request without chunks;
-
- // P2_EXTEND is set to signal that this APDU buffer extends, rather
- // than replaces, the current message buffer
- bool first_data_chunk = !(p2 & P2_EXTEND);
-
- handleSignTransaction(G_io_apdu_buffer + OFFSET_CDATA, G_io_apdu_buffer[OFFSET_LC], flags, first_data_chunk, more);
- } break;
-
- default:
- THROW(0x6D00);
- break;
- }
- }
- CATCH(EXCEPTION_IO_RESET) {
- THROW(EXCEPTION_IO_RESET);
- }
- CATCH_OTHER(e) {
- switch (e & 0xF000) {
- case 0x6000:
- sw = e;
- break;
- case 0x9000:
- // All is well
- sw = e;
- break;
- default:
- // Internal error
- sw = 0x6800 | (e & 0x7FF);
- break;
- }
- // Unexpected exception => report
- G_io_apdu_buffer[*tx] = sw >> 8;
- G_io_apdu_buffer[*tx + 1] = sw;
- *tx += 2;
- }
- FINALLY {
- }
- }
- END_TRY;
-}
-
void app_main(void) {
- volatile unsigned int rx = 0;
- volatile unsigned int tx = 0;
volatile unsigned int flags = 0;
- // Stores the information about the current command. Some commands expect
- // multiple APDUs before they become complete and executed.
- reset_app_context();
- reset_spi_buffer();
-
- // DESIGN NOTE: the bootloader ignores the way APDU are fetched. The only
- // goal is to retrieve APDU.
- // When APDU are to be fetched from multiple IOs, like NFC+USB+BLE, make
- // sure the io_event is called with a
- // switch event, before the apdu is replied to the bootloader. This avoid
- // APDU injection faults.
- for (;;) {
- volatile unsigned short sw = 0;
- BEGIN_TRY {
- TRY {
- rx = tx;
- tx = 0; // ensure no race in catch_other if io_exchange throws
- // an error
- rx = io_exchange(CHANNEL_APDU | flags, rx);
- flags = 0;
-
- // no apdu received, well, reset the session, and reset the
- // bootloader configuration
- if (rx == 0) {
- THROW(0x6982);
- }
-
- PRINTF("New APDU received:\n%.*H\n", rx, G_io_apdu_buffer);
-
- handleApdu(&flags, &tx, rx);
- }
- CATCH(EXCEPTION_IO_RESET) {
- THROW(EXCEPTION_IO_RESET);
- }
- CATCH_OTHER(e) {
- switch (e & 0xF000) {
- case 0x6000:
- sw = e;
- break;
- case 0x9000:
- // All is well
- sw = e;
- break;
- default:
- // Internal error
- sw = 0x6800 | (e & 0x7FF);
- break;
- }
- if (e != 0x9000) {
- flags &= ~IO_ASYNCH_REPLY;
- }
- // Unexpected exception => report
- G_io_apdu_buffer[tx] = sw >> 8;
- G_io_apdu_buffer[tx + 1] = sw;
- tx += 2;
- }
- FINALLY {
- }
- }
- END_TRY;
- }
- // return_to_dashboard
-}
-
-// override point, but nothing more to do
-void io_seproxyhal_display(const bagl_element_t *element) {
- io_seproxyhal_display_default((bagl_element_t*)element);
-}
-
-unsigned char io_event(unsigned char channel) {
- UNUSED(channel);
-
- // nothing done with the event, throw an error on the transport layer if
- // needed
+ // Length of APDU command received in G_io_apdu_buffer
+ int input_len = 0;
+ // Structured APDU command
+ command_t cmd;
- // can't have more than one tag in the reply, not supported yet.
- switch (G_io_seproxyhal_spi_buffer[0]) {
- case SEPROXYHAL_TAG_FINGER_EVENT:
- UX_FINGER_EVENT(G_io_seproxyhal_spi_buffer);
- break;
-
- case SEPROXYHAL_TAG_BUTTON_PUSH_EVENT:
- UX_BUTTON_PUSH_EVENT(G_io_seproxyhal_spi_buffer);
- break;
-
- case SEPROXYHAL_TAG_STATUS_EVENT:
- if (G_io_apdu_media == IO_APDU_MEDIA_USB_HID && !(U4BE(G_io_seproxyhal_spi_buffer, 3) & SEPROXYHAL_TAG_STATUS_EVENT_FLAG_USB_POWERED)) {
- THROW(EXCEPTION_IO_RESET);
- }
- // no break is intentional
- __attribute__((fallthrough));
- default:
- UX_DEFAULT_EVENT();
- break;
+ io_init();
- case SEPROXYHAL_TAG_DISPLAY_PROCESSED_EVENT:
- UX_DISPLAYED_EVENT({});
- break;
+ ui_main_menu();
- case SEPROXYHAL_TAG_TICKER_EVENT:
- UX_TICKER_EVENT(G_io_seproxyhal_spi_buffer,
- {
-#ifndef TARGET_NANOX
- if (UX_ALLOWED) {
- if (ux_step_count) {
- // prepare next screen
- ux_step = (ux_step+1)%ux_step_count;
- // redisplay screen
- UX_REDISPLAY();
- }
- }
-#endif // TARGET_NANOX
- });
- break;
- }
-
- // close the event if not done previously (by a display or whatever)
- if (!io_seproxyhal_spi_is_status_sent()) {
- io_seproxyhal_general_status();
- }
-
- // command has been processed, DO NOT reset the current APDU transport
- return 1;
-}
-
-
-unsigned short io_exchange_al(unsigned char channel, unsigned short tx_len) {
- switch (channel & ~(IO_FLAGS)) {
- case CHANNEL_KEYBOARD:
- break;
-
- // multiplexed io exchange over a SPI channel and TLV encapsulated protocol
- case CHANNEL_SPI:
- if (tx_len) {
- io_seproxyhal_spi_send(G_io_apdu_buffer, tx_len);
-
- if (channel & IO_RESET_AFTER_REPLIED) {
- reset();
- }
- return 0; // nothing received from the master so far (it's a tx
- // transaction)
- } else {
- return io_seproxyhal_spi_recv(G_io_apdu_buffer,
- sizeof(G_io_apdu_buffer), 0);
- }
-
- default:
- THROW(INVALID_PARAMETER);
- }
- return 0;
-}
+ reset_app_context();
-/**
- * Exit the application and go back to the dashboard.
- */
-void app_exit() {
- BEGIN_TRY_L(exit) {
- TRY_L(exit) {
- os_sched_exit(-1);
+ for (;;) {
+ // Receive command bytes in G_io_apdu_buffer
+ if ((input_len = io_recv_command()) < 0) {
+ PRINTF("=> io_recv_command failure\n");
+ return;
}
- FINALLY_L(exit) {
+ // Parse APDU command from G_io_apdu_buffer
+ if (!apdu_parser(&cmd, G_io_apdu_buffer, input_len)) {
+ PRINTF("=> /!\\ BAD LENGTH: %.*H\n", input_len, G_io_apdu_buffer);
+ io_send_sw(ERR_WRONG_DATA_LENGTH);
+ continue;
}
- }
- END_TRY_L(exit);
-}
-
-void nv_app_state_init() {
-
-}
-
-__attribute__((section(".boot"))) int main(void) {
- // exit critical section
- __asm volatile("cpsie i");
-
- // ensure exception will work as planned
- os_boot();
-
- for (;;) {
- UX_INIT();
-
+ PRINTF("=> CLA=%02X | INS=%02X | P1=%02X | P2=%02X | Lc=%02X | CData=%.*H\n",
+ cmd.cla,
+ cmd.ins,
+ cmd.p1,
+ cmd.p2,
+ cmd.lc,
+ cmd.lc,
+ cmd.data);
BEGIN_TRY {
TRY {
- io_seproxyhal_init();
-
- nv_app_state_init();
-
- USB_power(0);
- USB_power(1);
-
- ui_idle();
-
-#ifdef HAVE_BLE
- BLE_power(0, NULL);
- BLE_power(1, "Nano X");
-#endif // HAVE_BLE
-
- app_main();
- }
- CATCH(EXCEPTION_IO_RESET) {
- // reset IO and UX before continuing
- continue;
+ // Dispatch structured APDU command to handler
+ if (apdu_dispatcher(&cmd, &flags) < 0) {
+ PRINTF("=> apdu_dispatcher failure\n");
+ return;
+ }
}
- CATCH_ALL {
- break;
+ CATCH_OTHER(e) {
+ PRINTF("=> exception: %d\n", e);
+ io_send_sw(e);
+ return;
}
FINALLY {
}
}
END_TRY;
}
- app_exit();
- return 0;
-}
+}
\ No newline at end of file
diff --git a/src/menu.c b/src/menu.c
deleted file mode 100644
index 45d143f..0000000
--- a/src/menu.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "menu.h"
-#include "os.h"
-
-//////////////////////////////////////////////////////////////////////
-UX_STEP_NOCB(
- ux_idle_flow_1_step,
- nn,
- {
- "Application",
- "is ready",
- });
-UX_STEP_NOCB(
- ux_idle_flow_3_step,
- bn,
- {
- "Version",
- APPVERSION,
- });
-UX_STEP_VALID(
- ux_idle_flow_4_step,
- pb,
- os_sched_exit(-1),
- {
- &C_icon_dashboard_x,
- "Quit",
- });
-UX_FLOW(ux_idle_flow,
- &ux_idle_flow_1_step,
- &ux_idle_flow_3_step,
- &ux_idle_flow_4_step,
- FLOW_LOOP
-);
-
-void ui_idle(void) {
- // reserve a display stack slot if none yet
- if(G_ux.stack_count == 0) {
- ux_stack_push();
- }
- ux_flow_init(0, ux_idle_flow, NULL);
-}
diff --git a/src/menu.h b/src/menu.h
deleted file mode 100644
index e7a5c46..0000000
--- a/src/menu.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#include "globals.h"
-
-#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-#include "glyphs.h"
-#endif
-
-#ifndef _MENU_H_
-#define _MENU_H_
-
-void ui_idle(void);
-
-#endif
diff --git a/src/message.c b/src/message.c
index e21de54..b2d9cc6 100644
--- a/src/message.c
+++ b/src/message.c
@@ -4,11 +4,16 @@
#include "slice_data.h"
#include "byte_stream.h"
#include "contract.h"
+#include "format.h"
#define ROOT_CELL_INDEX 0
#define GIFT_CELL_INDEX 1
-void deserialize_array(uint8_t* in, uint8_t in_size, uint16_t offset, uint8_t* out, uint8_t out_size) {
+void deserialize_array(uint8_t* in,
+ uint8_t in_size,
+ uint16_t offset,
+ uint8_t* out,
+ uint8_t out_size) {
uint8_t shift = offset % 8;
uint8_t first_data_byte = offset / 8;
for (uint16_t i = first_data_byte, j = 0; j < out_size; ++i, ++j) {
@@ -35,7 +40,7 @@ void deserialize_address(struct SliceData_t* slice, int8_t* wc, uint8_t* address
uint8_t anycast = SliceData_get_next_bit(slice);
UNUSED(anycast);
- *wc = (int8_t)SliceData_get_next_byte(slice);
+ *wc = (int8_t) SliceData_get_next_byte(slice);
uint8_t* data = SliceData_begin(slice);
uint16_t offset = SliceData_get_cursor(slice);
@@ -57,18 +62,25 @@ void deserialize_value(struct SliceData_t* slice, uint8_t* value, uint8_t value_
}
void set_dst_address(uint8_t wc, const uint8_t* address) {
- char wc_temp[6]; // snprintf always returns zero
- snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t)wc);
+ char wc_temp[6]; // snprintf always returns zero
+ snprintf(wc_temp, sizeof(wc_temp), "%d:", (int8_t) wc);
int wc_len = strlen(wc_temp);
char* address_str = data_context.sign_tr_context.address_str;
memcpy(address_str, wc_temp, wc_len);
address_str += wc_len;
- format_hex(address, ADDRESS_LENGTH, address_str, sizeof(data_context.sign_tr_context.address_str));
+ format_hex(address,
+ ADDRESS_LENGTH,
+ address_str,
+ sizeof(data_context.sign_tr_context.address_str));
}
-void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uint8_t decimals, const char* ticker) {
+void set_amount(const uint8_t* amount,
+ uint8_t amount_length,
+ uint8_t flags,
+ uint8_t decimals,
+ const char* ticker) {
char* amount_str = data_context.sign_tr_context.amount_str;
size_t amount_str_size = sizeof(data_context.sign_tr_context.amount_str);
@@ -77,8 +89,10 @@ void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uin
switch (flags) {
case NORMAL_FLAG: {
const char* space = " ";
- uint8_t text_size = convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str);
- VALIDATE(amount_str_size >= text_size + strlen(space) + strlen(ticker), ERR_INVALID_MESSAGE);
+ uint8_t text_size =
+ convert_hex_amount_to_displayable(amount, decimals, amount_length, amount_str);
+ VALIDATE(amount_str_size >= text_size + strlen(space) + strlen(ticker),
+ ERR_INVALID_MESSAGE);
strncpy(amount_str + text_size, space, strlen(space));
strncpy(amount_str + text_size + strlen(space), ticker, strlen(ticker));
@@ -106,10 +120,15 @@ void set_amount(const uint8_t* amount, uint8_t amount_length, uint8_t flags, uin
void set_transaction_id(const uint8_t* transaction_id) {
char* transaction_id_str = data_context.sign_tr_context.transaction_id_str;
memset(transaction_id_str, 0, sizeof(data_context.sign_tr_context.transaction_id_str));
- format_hex(transaction_id, TRANSACTION_ID_LENGTH, transaction_id_str, sizeof(data_context.sign_tr_context.transaction_id_str));
+ format_hex(transaction_id,
+ TRANSACTION_ID_LENGTH,
+ transaction_id_str,
+ sizeof(data_context.sign_tr_context.transaction_id_str));
}
-void deserialize_int_message_header(struct SliceData_t* slice, uint8_t flags, SignTransactionContext_t* ctx) {
+void deserialize_int_message_header(struct SliceData_t* slice,
+ uint8_t flags,
+ SignTransactionContext_t* ctx) {
uint8_t int_msg = SliceData_get_next_bit(slice);
VALIDATE(!int_msg, ERR_INVALID_MESSAGE);
@@ -160,11 +179,13 @@ void deserialize_int_message_header(struct SliceData_t* slice, uint8_t flags, Si
UNUSED(created_at);
}
-
-int deserialize_token_body(struct SliceData_t* slice, struct SliceData_t* ref_slice, SignTransactionContext_t* ctx) {
+int deserialize_token_body(struct SliceData_t* slice,
+ struct SliceData_t* ref_slice,
+ SignTransactionContext_t* ctx) {
// FunctionId
if (SliceData_remaining_bits(slice) < sizeof(uint32_t) * 8) {
- if (!ref_slice || !ref_slice->data || (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) {
+ if (!ref_slice || !ref_slice->data ||
+ (SliceData_remaining_bits(ref_slice) < sizeof(uint32_t) * 8)) {
// Empty payload is ok
return SIGN_TRANSACTION_FLOW_TRANSFER;
}
@@ -235,7 +256,11 @@ int deserialize_token_body(struct SliceData_t* slice, struct SliceData_t* ref_sl
return sign_transaction_flow;
}
-int deserialize_multisig_params(struct SliceData_t* slice, uint32_t function_id, uint8_t wc, uint8_t* address, SignTransactionContext_t* ctx) {
+int deserialize_multisig_params(struct SliceData_t* slice,
+ uint32_t function_id,
+ uint8_t wc,
+ uint8_t* address,
+ SignTransactionContext_t* ctx) {
int sign_transaction_flow = SIGN_TRANSACTION_FLOW_ERROR;
switch (function_id) {
@@ -331,10 +356,16 @@ void prepare_payload_hash(BocContext_t* bc) {
}
if (!data_context.sign_tr_context.sign_with_chain_id) {
- memcpy(data_context.sign_tr_context.to_sign, &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH);
+ memcpy(data_context.sign_tr_context.to_sign,
+ &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE],
+ TO_SIGN_LENGTH);
} else {
- memcpy(data_context.sign_tr_context.to_sign, data_context.sign_tr_context.chain_id, CHAIN_ID_LENGTH);
- memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH, &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE], TO_SIGN_LENGTH);
+ memcpy(data_context.sign_tr_context.to_sign,
+ data_context.sign_tr_context.chain_id,
+ CHAIN_ID_LENGTH);
+ memcpy(data_context.sign_tr_context.to_sign + CHAIN_ID_LENGTH,
+ &bc->hashes[ROOT_CELL_INDEX * HASH_SIZE],
+ TO_SIGN_LENGTH);
}
}
@@ -372,9 +403,13 @@ uint32_t deserialize_contract_header(struct SliceData_t* slice) {
return function_id;
}
-void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, struct Cell_t* cell, uint8_t wc, uint8_t* address) {
+void prepend_address_to_cell(uint8_t* cell_buffer,
+ uint16_t cell_buffer_size,
+ struct Cell_t* cell,
+ uint8_t wc,
+ uint8_t* address) {
uint16_t bit_len = Cell_bit_len(cell);
- bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8)
+ bit_len += 267; // Prefix(2) + Anycast(1) + WorkchainId(8) + Address(32 * 8)
uint8_t d1 = Cell_get_d1(cell);
uint8_t d2 = ((bit_len >> 2) & 0b11111110) | (bit_len % 8 != 0);
@@ -386,11 +421,11 @@ void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, st
SliceData_init(&slice, cell_buffer + CELL_DATA_OFFSET, cell_buffer_size);
// Append prefix
- uint8_t prefix[] = { 0x80 }; // $100 prefix AddrStd
+ uint8_t prefix[] = {0x80}; // $100 prefix AddrStd
SliceData_append(&slice, prefix, 3, false);
// Append workchain
- uint8_t wc_buf[] = { wc };
+ uint8_t wc_buf[] = {wc};
SliceData_append(&slice, wc_buf, 8, false);
// Append address
@@ -415,7 +450,10 @@ void prepend_address_to_cell(uint8_t* cell_buffer, uint16_t cell_buffer_size, st
cell->cell_begin = cell_buffer;
}
-int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint8_t* prepend_address) {
+int prepare_to_sign(struct ByteStream_t* src,
+ uint8_t wc,
+ uint8_t* address,
+ uint8_t* prepend_address) {
// Init context
BocContext_t* bc = &boc_context;
DataContext_t* dc = &data_context;
@@ -465,7 +503,8 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint
SliceData_t ref_slice;
SliceData_from_cell(&ref_slice, ref_cell);
- sign_transaction_flow = deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context);
+ sign_transaction_flow =
+ deserialize_token_body(&gift_slice, &ref_slice, &dc->sign_tr_context);
}
// Calculate payload hash to sign
@@ -494,7 +533,11 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint
SliceData_from_cell(&gift_slice, gift_cell);
}
- sign_transaction_flow = deserialize_multisig_params(&gift_slice, function_id, wc, address, &dc->sign_tr_context);
+ sign_transaction_flow = deserialize_multisig_params(&gift_slice,
+ function_id,
+ wc,
+ address,
+ &dc->sign_tr_context);
uint8_t gift_refs_count;
Cell_get_refs(gift_cell, &gift_refs_count);
@@ -508,7 +551,8 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint
SliceData_from_cell(&body_slice, body_cell);
if (!SliceData_is_empty(&body_slice)) {
- sign_transaction_flow = deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context);
+ sign_transaction_flow =
+ deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context);
}
}
@@ -530,7 +574,11 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint
SliceData_t gift_slice;
SliceData_from_cell(&gift_slice, gift_cell);
- sign_transaction_flow = deserialize_multisig_params(&gift_slice, function_id, wc, address, &dc->sign_tr_context);
+ sign_transaction_flow = deserialize_multisig_params(&gift_slice,
+ function_id,
+ wc,
+ address,
+ &dc->sign_tr_context);
uint8_t gift_refs_count;
Cell_get_refs(gift_cell, &gift_refs_count);
@@ -544,13 +592,18 @@ int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint
SliceData_from_cell(&body_slice, body_cell);
if (!SliceData_is_empty(&body_slice)) {
- sign_transaction_flow = deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context);
+ sign_transaction_flow =
+ deserialize_token_body(&body_slice, NULL, &dc->sign_tr_context);
}
}
// Prepend address to root cell
- uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128)
- prepend_address_to_cell(cell_buffer, sizeof(cell_buffer), root_cell, wc, prepend_address);
+ uint8_t cell_buffer[130]; // d1(1) + d2(1) + data(128)
+ prepend_address_to_cell(cell_buffer,
+ sizeof(cell_buffer),
+ root_cell,
+ wc,
+ prepend_address);
// Calculate payload hash to sign
prepare_payload_hash(bc);
diff --git a/src/message.h b/src/message.h
index cd48c84..296f600 100644
--- a/src/message.h
+++ b/src/message.h
@@ -6,6 +6,9 @@
#define DEFAULT_WORKCHAIN_ID 0
struct ByteStream_t;
-int prepare_to_sign(struct ByteStream_t* src, uint8_t wc, uint8_t* address, uint8_t* prepend_address);
+int prepare_to_sign(struct ByteStream_t* src,
+ uint8_t wc,
+ uint8_t* address,
+ uint8_t* prepend_address);
#endif
diff --git a/src/sign.c b/src/sign.c
deleted file mode 100644
index 37d2c3e..0000000
--- a/src/sign.c
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "apdu_constants.h"
-#include "utils.h"
-#include "errors.h"
-
-static const char SIGN_MAGIC[] = {0xFF, 0xFF, 0xFF, 0xFF };
-
-static uint8_t set_result_sign() {
- cx_ecfp_private_key_t privateKey;
- SignContext_t* context = &data_context.sign_context;
-
- BEGIN_TRY {
- TRY {
- get_private_key(context->account_number, &privateKey);
- cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL);
- } FINALLY {
- explicit_bzero(&privateKey, sizeof(privateKey));
- }
- }
- END_TRY;
-
- uint8_t tx = 0;
- G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH;
- memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH);
- tx += SIGNATURE_LENGTH;
- return tx;
-}
-
-UX_STEP_NOCB(
- ux_sign_flow_1_step,
- pnn,
- {
- &C_icon_certificate,
- "Sign",
- "message",
- });
-UX_STEP_NOCB(
- ux_sign_flow_2_step,
- bnnn_paging,
- {
- .title = "Message",
- .text = data_context.sign_context.to_sign_str,
- });
-UX_STEP_CB(
- ux_sign_flow_3_step,
- pbb,
- send_response(0, false),
- {
- &C_icon_crossmark,
- "Cancel",
- "signature",
- });
-UX_STEP_CB(
- ux_sign_flow_4_step,
- pbb,
- send_response(set_result_sign(), true),
- {
- &C_icon_validate_14,
- "Sign",
- "message",
- });
-
-UX_FLOW(ux_sign_flow,
- &ux_sign_flow_1_step,
- &ux_sign_flow_2_step,
- &ux_sign_flow_3_step,
- &ux_sign_flow_4_step
-);
-
-void handleSign(uint8_t *dataBuffer, __attribute__((unused)) uint16_t dataLength, volatile unsigned int *flags) {
- SignContext_t* context = &data_context.sign_context;
-
- size_t offset = 0;
-
- VALIDATE(dataLength >= offset + sizeof(context->account_number), ERR_INVALID_REQUEST);
- context->account_number = readUint32BE(dataBuffer + offset);
- offset += sizeof(context->account_number);
-
- VALIDATE(dataLength >= offset + TO_SIGN_LENGTH, ERR_INVALID_REQUEST);
- memcpy(context->to_sign, SIGN_MAGIC, SIGN_MAGIC_LENGTH);
- memcpy(context->to_sign + SIGN_MAGIC_LENGTH, dataBuffer + offset, TO_SIGN_LENGTH);
- format_hex(context->to_sign, SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH, context->to_sign_str, sizeof(context->to_sign_str));
-
- ux_flow_init(0, ux_sign_flow, NULL);
- *flags |= IO_ASYNCH_REPLY;
-}
diff --git a/src/sign_transaction.c b/src/sign_transaction.c
deleted file mode 100644
index 6636886..0000000
--- a/src/sign_transaction.c
+++ /dev/null
@@ -1,259 +0,0 @@
-#include "apdu_constants.h"
-#include "utils.h"
-#include "errors.h"
-#include "byte_stream.h"
-#include "message.h"
-#include "contract.h"
-
-static uint8_t set_result_sign_transaction() {
- cx_ecfp_private_key_t privateKey;
- SignTransactionContext_t* context = &data_context.sign_tr_context;
-
- BEGIN_TRY {
- TRY {
- get_private_key(context->account_number, &privateKey);
- if (!context->sign_with_chain_id) {
- cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL);
- } else {
- cx_eddsa_sign(&privateKey, CX_LAST, CX_SHA512, context->to_sign, CHAIN_ID_LENGTH + TO_SIGN_LENGTH, NULL, 0, context->signature, SIGNATURE_LENGTH, NULL);
- }
- } FINALLY {
- explicit_bzero(&privateKey, sizeof(privateKey));
- }
- }
- END_TRY;
-
- uint8_t tx = 0;
- G_io_apdu_buffer[tx++] = SIGNATURE_LENGTH;
- memmove(G_io_apdu_buffer + tx, context->signature, SIGNATURE_LENGTH);
- tx += SIGNATURE_LENGTH;
- return tx;
-}
-
-UX_STEP_NOCB(
- ux_sign_transaction_intro,
- pnn,
- {
- &C_icon_eye,
- "Review",
- "transaction",
- });
-UX_STEP_NOCB(
- ux_sign_transaction_burn,
- bnnn_paging,
- {
- .title = "Action",
- .text = "Burn"
- });
-UX_STEP_NOCB(
- ux_sign_transaction_deploy,
- bnnn_paging,
- {
- .title = "Action",
- .text = "Deploy"
- });
-UX_STEP_NOCB(
- ux_sign_transaction_confirm,
- bnnn_paging,
- {
- .title = "Action",
- .text = "Confirm"
- });
-UX_STEP_NOCB(
- ux_sign_transaction_transfer,
- bnnn_paging,
- {
- .title = "Action",
- .text = "Transfer"
- });
-UX_STEP_NOCB(
- ux_sign_transaction_amount,
- bnnn_paging,
- {
- .title = "Amount",
- .text = data_context.sign_tr_context.amount_str,
- });
-UX_STEP_NOCB(
- ux_sign_transaction_address,
- bnnn_paging,
- {
- .title = "Address",
- .text = data_context.sign_tr_context.address_str,
- });
-UX_STEP_NOCB(
- ux_sign_transaction_transaction_id,
- bnnn_paging,
- {
- .title = "Transaction id",
- .text = data_context.sign_tr_context.transaction_id_str,
- });
-UX_STEP_CB(
- ux_sign_transaction_accept,
- pbb,
- send_response(set_result_sign_transaction(), true),
- {
- &C_icon_validate_14,
- "Accept",
- "and send",
- });
-UX_STEP_CB(
- ux_sign_transaction_reject,
- pb,
- send_response(0, false),
- {
- &C_icon_crossmark,
- "Reject",
- });
-
-UX_FLOW(ux_sign_transaction_burn_flow,
- &ux_sign_transaction_intro,
- &ux_sign_transaction_burn,
- &ux_sign_transaction_amount,
- &ux_sign_transaction_accept,
- &ux_sign_transaction_reject
-);
-
-UX_FLOW(ux_sign_transaction_deploy_flow,
- &ux_sign_transaction_intro,
- &ux_sign_transaction_deploy,
- &ux_sign_transaction_address,
- &ux_sign_transaction_accept,
- &ux_sign_transaction_reject
-);
-
-UX_FLOW(ux_sign_transaction_confirm_flow,
- &ux_sign_transaction_intro,
- &ux_sign_transaction_confirm,
- &ux_sign_transaction_transaction_id,
- &ux_sign_transaction_accept,
- &ux_sign_transaction_reject
-);
-
-UX_FLOW(ux_sign_transaction_transfer_flow,
- &ux_sign_transaction_intro,
- &ux_sign_transaction_transfer,
- &ux_sign_transaction_amount,
- &ux_sign_transaction_address,
- &ux_sign_transaction_accept,
- &ux_sign_transaction_reject
-);
-
-int handleSignTransaction(uint8_t *dataBuffer, uint16_t dataLength, volatile unsigned int *flags, bool is_first_chunk, bool more) {
- if (is_first_chunk) {
- reset_app_context();
- }
-
- SignTransactionContext_t *context = &data_context.sign_tr_context;
-
- size_t offset = 0;
-
- if (is_first_chunk) {
- VALIDATE(dataLength >= offset + sizeof(context->account_number), ERR_INVALID_REQUEST);
- context->account_number = readUint32BE(dataBuffer + offset);
- offset += sizeof(context->account_number);
-
- VALIDATE(dataLength >= offset + sizeof(context->origin_wallet_type), ERR_INVALID_REQUEST);
- context->origin_wallet_type = dataBuffer[offset];
- offset += sizeof(context->origin_wallet_type);
-
- VALIDATE(dataLength >= offset + sizeof(context->decimals), ERR_INVALID_REQUEST);
- context->decimals = dataBuffer[offset];
- offset += sizeof(context->decimals);
-
- VALIDATE(dataLength >= offset + sizeof(uint8_t), ERR_INVALID_REQUEST);
- uint8_t ticker_len = dataBuffer[offset];
- offset += sizeof(ticker_len);
-
- VALIDATE(ticker_len != 0 && ticker_len <= MAX_TICKER_LEN, ERR_TICKER_LENGTH);
-
- VALIDATE(dataLength >= offset + ticker_len, ERR_INVALID_REQUEST);
- memcpy(context->ticker, dataBuffer + offset, ticker_len);
- offset += ticker_len;
-
- VALIDATE(dataLength >= offset + sizeof(uint8_t), ERR_INVALID_REQUEST);
- uint8_t metadata = dataBuffer[offset];
- offset += sizeof(metadata);
-
- // Read wallet type if present
- if (metadata & FLAG_WITH_WALLET_ID) {
- VALIDATE(dataLength >= offset + sizeof(context->current_wallet_type), ERR_INVALID_REQUEST);
- context->current_wallet_type = dataBuffer[offset];
- offset += sizeof(context->current_wallet_type);
- } else {
- context->current_wallet_type = context->origin_wallet_type;
- }
-
- // Get address
- get_address(context->account_number, context->origin_wallet_type, context->address);
- memset(&boc_context, 0, sizeof(boc_context));
-
- // Read wc if present
- context->wc = DEFAULT_WORKCHAIN_ID;
- if (metadata & FLAG_WITH_WORKCHAIN_ID) {
- VALIDATE(dataLength >= offset + sizeof(context->wc), ERR_INVALID_REQUEST);
- context->wc = dataBuffer[offset];
- offset += sizeof(context->wc);
- }
-
- // Read initial address if present
- if (metadata & FLAG_WITH_ADDRESS) {
- VALIDATE(dataLength >= offset + sizeof(context->address), ERR_INVALID_REQUEST);
- memcpy(context->prepend_address, dataBuffer + offset, ADDRESS_LENGTH);
- offset += sizeof(context->address);
- } else {
- memcpy(context->prepend_address, context->address, ADDRESS_LENGTH);
- }
-
- // Read chain id if present
- if (metadata & FLAG_WITH_CHAIN_ID) {
- context->sign_with_chain_id = true;
-
- VALIDATE(dataLength >= offset + sizeof(context->chain_id), ERR_INVALID_REQUEST);
- memcpy(context->chain_id, dataBuffer + offset, CHAIN_ID_LENGTH);
- offset += sizeof(context->chain_id);
- } else {
- context->sign_with_chain_id = false;
- }
- }
- // offset is a pointer to dataBuffer, or the number of bytes we moved. here + offset means start of the message
- // we need to save data to a context buffer and add msg_length to offset of this buffer
- uint8_t* msg_begin = dataBuffer + offset;
-
- // Since we check LC dataLength can not be manipulated
- uint16_t msg_length = dataLength - offset;
-
- if (msg_begin && msg_length > 0) { // if data exists
- VALIDATE(context->data_offset + msg_length < sizeof(context->data) , ERR_INVALID_DATA);
- memcpy(context->data + context->data_offset, msg_begin, msg_length);
- context->data_offset += msg_length; // add length of the new message to our context offset
- }
-
- if (more) {
- THROW(SUCCESS);
- }
-
- // Handle transaction
- ByteStream_t src;
- ByteStream_init(&src, context->data, context->data_offset);
-
- int flow = prepare_to_sign(&src, context->wc, context->address, context->prepend_address);
-
- switch (flow) {
- case SIGN_TRANSACTION_FLOW_TRANSFER:
- ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL);
- break;
- case SIGN_TRANSACTION_FLOW_DEPLOY:
- ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL);
- break;
- case SIGN_TRANSACTION_FLOW_CONFIRM:
- ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL);
- break;
- case SIGN_TRANSACTION_FLOW_BURN:
- ux_flow_init(0, ux_sign_transaction_burn_flow, NULL);
- break;
- default:
- THROW(ERR_INVALID_REQUEST);
- }
-
- *flags |= IO_ASYNCH_REPLY;
-}
diff --git a/src/slice_data.c b/src/slice_data.c
index e34d94f..6eb9f6e 100644
--- a/src/slice_data.c
+++ b/src/slice_data.c
@@ -66,7 +66,7 @@ uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint
}
ret = (ret >> (8 - r)) >> (8 - bits);
- return (uint8_t)ret;
+ return (uint8_t) ret;
}
}
@@ -161,8 +161,7 @@ void SliceData_append(struct SliceData_t* self, uint8_t* in, uint16_t bits, bool
uint16_t offset = self->data_window_start;
if (offset % 8 == 0 || bytes == 0) {
memcpy(self->data + offset / 8, in, bytes ? bytes : 1);
- }
- else {
+ } else {
uint8_t shift = offset % 8;
uint8_t first_data_byte = offset / 8;
uint8_t prev = 0;
diff --git a/src/text b/src/text
new file mode 100644
index 0000000..4b62c2e
--- /dev/null
+++ b/src/text
@@ -0,0 +1,385 @@
+/usr/bin/docker run --name cf2912b6eda476ca142b2814c965c07_cbf8c6 --label 119993 --workdir /github/workspace --rm -e "INPUT_SOURCE" -e "INPUT_EXTENSIONS" -e "INPUT_CLANGFORMATVERSION" -e "INPUT_EXCLUDE" -e "INPUT_STYLE" -e "INPUT_INPLACE" -e "HOME" -e "GITHUB_JOB" -e "GITHUB_REF" -e "GITHUB_SHA" -e "GITHUB_REPOSITORY" -e "GITHUB_REPOSITORY_OWNER" -e "GITHUB_REPOSITORY_OWNER_ID" -e "GITHUB_RUN_ID" -e "GITHUB_RUN_NUMBER" -e "GITHUB_RETENTION_DAYS" -e "GITHUB_RUN_ATTEMPT" -e "GITHUB_REPOSITORY_ID" -e "GITHUB_ACTOR_ID" -e "GITHUB_ACTOR" -e "GITHUB_TRIGGERING_ACTOR" -e "GITHUB_WORKFLOW" -e "GITHUB_HEAD_REF" -e "GITHUB_BASE_REF" -e "GITHUB_EVENT_NAME" -e "GITHUB_SERVER_URL" -e "GITHUB_API_URL" -e "GITHUB_GRAPHQL_URL" -e "GITHUB_REF_NAME" -e "GITHUB_REF_PROTECTED" -e "GITHUB_REF_TYPE" -e "GITHUB_WORKFLOW_REF" -e "GITHUB_WORKFLOW_SHA" -e "GITHUB_WORKSPACE" -e "GITHUB_ACTION" -e "GITHUB_EVENT_PATH" -e "GITHUB_ACTION_REPOSITORY" -e "GITHUB_ACTION_REF" -e "GITHUB_PATH" -e "GITHUB_ENV" -e "GITHUB_STEP_SUMMARY" -e "GITHUB_STATE" -e "GITHUB_OUTPUT" -e "RUNNER_OS" -e "RUNNER_ARCH" -e "RUNNER_NAME" -e "RUNNER_ENVIRONMENT" -e "RUNNER_TOOL_CACHE" -e "RUNNER_TEMP" -e "RUNNER_WORKSPACE" -e "ACTIONS_RUNTIME_URL" -e "ACTIONS_RUNTIME_TOKEN" -e "ACTIONS_CACHE_URL" -e "ACTIONS_RESULTS_URL" -e GITHUB_ACTIONS=true -e CI=true --network github_network_87a5535abc654fe98bcb659114df86d4 -v "/var/run/docker.sock":"/var/run/docker.sock" -v "/home/runner/work/_temp/_github_home":"/github/home" -v "/home/runner/work/_temp/_github_workflow":"/github/workflow" -v "/home/runner/work/_temp/_runner_file_commands":"/github/file_commands" -v "/home/runner/work/app-everscale/app-everscale":"/github/workspace" 119993:0cf2912b6eda476ca142b2814c965c07 "--clang-format-executable" "/clang-format/clang-format12" "-r" "--color" "always" "--style" "file" "--inplace" "false" "--extensions" "h,c" "--exclude" "none" "./src"
+Processing 26 files: ./src/menu.c, ./src/sign.c, ./src/main.c, ./src/contract.c, ./src/contract.h, ./src/hashmap_label.c, ./src/message.h, ./src/menu.h, ./src/apdu_constants.h, ./src/message.c, ./src/cell.h, ./src/slice_data.c, ./src/byte_stream.c, ./src/get_app_configuration.c, ./src/slice_data.h, ./src/get_public_key.c, ./src/globals.c, ./src/sign_transaction.c, ./src/globals.h, ./src/errors.h, ./src/cell.c, ./src/get_address.c, ./src/utils.c, ./src/byte_stream.h, ./src/hashmap_label.h, ./src/utils.h
+--- ./src/message.h (original)
++++ ./src/message.h (reformatted)
+@@ -6,6 +6,9 @@
+#define DEFAULT_WORKCHAIN_ID 0
+
+ struct ByteStream_t;
+-
+ int
+ prepare_to_sign(struct ByteStream_t* src,
+ uint8_t wc,
+ uint8_t* address,
+ uint8_t* prepend_address);
++
+ int
+ prepare_to_sign(struct ByteStream_t* src,
+ +uint8_t wc,
+ +uint8_t* address,
+ +uint8_t* prepend_address);
+
+#endif
+-- -./ src / contract.h(original)++ +./ src / contract.h(reformatted) @ @-13, 21 + 13,
+ 21 @ @
+#define SIGN_TRANSACTION_FLOW_BURN 3
+
+ enum {
+ -WALLET_V3 = 0,
+ -EVER_WALLET = 1,
+ -SAFE_MULTISIG_WALLET = 2,
+ +WALLET_V3 = 0,
+ +EVER_WALLET = 1,
+ +SAFE_MULTISIG_WALLET = 2,
+ SAFE_MULTISIG_WALLET_24H = 3,
+ -SETCODE_MULTISIG_WALLET = 4,
+ -BRIDGE_MULTISIG_WALLET = 5,
+ -SURF_WALLET = 6,
+ -MULTISIG_2 = 7,
+ -MULTISIG_2_1 = 8,
+ +SETCODE_MULTISIG_WALLET = 4,
+ +BRIDGE_MULTISIG_WALLET = 5,
+ +SURF_WALLET = 6,
+ +MULTISIG_2 = 7,
+ +MULTISIG_2_1 = 8,
+ };
+
+enum {
+ -MULTISIG_DEPLOY_TRANSACTION = 1813932348,
+ -MULTISIG_SEND_TRANSACTION = 1290691692,
+ -MULTISIG_SUBMIT_TRANSACTION = 320701133,
+ +MULTISIG_DEPLOY_TRANSACTION = 1813932348,
+ +MULTISIG_SEND_TRANSACTION = 1290691692,
+ +MULTISIG_SUBMIT_TRANSACTION = 320701133,
+ MULTISIG_CONFIRM_TRANSACTION = 447168749,
+
+ MULTISIG2_DEPLOY_TRANSACTION = 733015951,
+ @ @-35,
+ 16 + 35,
+ 12 @ @
+};
+
+enum {
+ -TOKEN_BURN = 1445284013, // Burn
+ -TOKEN_TRANSFER = 1944199491, // Deploy
+ +TOKEN_BURN = 1445284013, // Burn
+ +TOKEN_TRANSFER = 1944199491, // Deploy
+ TOKEN_TRANSFER_TO_WALLET = 1185535980, // Ordinary transfer
+};
+
+- enum { -NORMAL_FLAG = 3, -ALL_BALANCE_FLAG = 128, -ALL_BALANCE_AND_DELETE_FLAG = 160 - };
++ enum { NORMAL_FLAG = 3, ALL_BALANCE_FLAG = 128, ALL_BALANCE_AND_DELETE_FLAG = 160 };
+
+struct ByteStream_t;
+void deserialize_cells_tree(struct ByteStream_t* src);
+-- -./ src / apdu_constants.h(original)++ +./ src / apdu_constants.h(reformatted) @ @-23, 29 + 23,
+ 29 @ @
+#define OFFSET_LC 4
+#define OFFSET_CDATA 5
+
+ -void handleGetAppConfiguration(uint8_t p1,
+ -uint8_t p2,
+ -uint8_t* dataBuffer,
+ -uint16_t dataLength,
+ -volatile unsigned int* flags,
+ -volatile unsigned int* tx);
+- void
+handleGetPublicKey(uint8_t p1,
+ -uint8_t p2,
+ -uint8_t* dataBuffer,
+ -uint16_t dataLength,
+ -volatile unsigned int* flags,
+ -volatile unsigned int* tx);
+- void
+handleGetAddress(uint8_t p1,
+ -uint8_t p2,
+ -uint8_t* dataBuffer,
+ -uint16_t dataLength,
+ -volatile unsigned int* flags,
+ -volatile unsigned int* tx);
+- void handleSign(uint8_t* dataBuffer, uint16_t dataLength, volatile unsigned int* flags);
+- void
+handleSignTransaction(uint8_t* dataBuffer,
+ -uint16_t dataLength,
+ -volatile unsigned int* flags,
+ -bool is_first_chunk,
+ -bool more);
++ void
+handleGetAppConfiguration(uint8_t p1,
+ +uint8_t p2,
+ +uint8_t* dataBuffer,
+ +uint16_t dataLength,
+ +volatile unsigned int* flags,
+ +volatile unsigned int* tx);
++ void
+handleGetPublicKey(uint8_t p1,
+ +uint8_t p2,
+ +uint8_t* dataBuffer,
+ +uint16_t dataLength,
+ +volatile unsigned int* flags,
+ +volatile unsigned int* tx);
++ void
+handleGetAddress(uint8_t p1,
+ +uint8_t p2,
+ +uint8_t* dataBuffer,
+ +uint16_t dataLength,
+ +volatile unsigned int* flags,
+ +volatile unsigned int* tx);
++ void handleSign(uint8_t* dataBuffer, uint16_t dataLength, volatile unsigned int* flags);
++ void
+handleSignTransaction(uint8_t* dataBuffer,
+ +uint16_t dataLength,
+ +volatile unsigned int* flags,
+ +bool is_first_chunk,
+ +bool more);
+
+#endif
+-- -./ src / cell.h(original)++ +./ src / cell.h(reformatted) @ @-12, 14 + 12,
+ 14 @ @uint16_t cell_length;
+}
+Cell_t;
+
+- void Cell_init(struct Cell_t* self, uint8_t* cell_begin, uint16_t cell_length);
+- uint8_t Cell_get_d1(const struct Cell_t* self);
+- uint8_t Cell_get_d2(const struct Cell_t* self);
+- uint8_t Cell_get_data_size(const struct Cell_t* self);
++ void Cell_init(struct Cell_t* self, uint8_t* cell_begin, uint16_t cell_length);
++ uint8_t Cell_get_d1(const struct Cell_t* self);
++ uint8_t Cell_get_d2(const struct Cell_t* self);
++ uint8_t Cell_get_data_size(const struct Cell_t* self);
+uint8_t* Cell_get_data(const struct Cell_t* self);
+uint8_t* Cell_get_refs(const struct Cell_t* self, uint8_t* refs_count);
+uint16_t Cell_bit_len(struct Cell_t* self);
+uint16_t deserialize_cell(struct Cell_t* cell, const uint8_t cell_index, const uint8_t cells_count);
+- void calc_cell_hash(Cell_t* cell, const uint8_t cell_index);
++ void calc_cell_hash(Cell_t* cell, const uint8_t cell_index);
+
+#endif
+-- -./ src / slice_data.h(original)++ +./ src / slice_data.h(reformatted) @ @-13, 22 + 13,
+ 22 @ @
+
+ struct Cell_t;
+
+- void SliceData_init(struct SliceData_t* self, uint8_t* data, uint16_t data_size_bytes);
+- void SliceData_from_cell(struct SliceData_t* self, struct Cell_t* cell);
+- void SliceData_fill(struct SliceData_t* self, uint8_t value, uint16_t data_size_bytes);
+- void SliceData_truncate(struct SliceData_t* self, uint16_t size);
++ void SliceData_init(struct SliceData_t* self, uint8_t* data, uint16_t data_size_bytes);
++ void SliceData_from_cell(struct SliceData_t* self, struct Cell_t* cell);
++ void SliceData_fill(struct SliceData_t* self, uint8_t value, uint16_t data_size_bytes);
++ void SliceData_truncate(struct SliceData_t* self, uint16_t size);
+uint16_t SliceData_remaining_bits(const struct SliceData_t* self);
+- void SliceData_move_by(struct SliceData_t* self, uint16_t offset);
+- uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint8_t bits);
+- uint8_t SliceData_get_next_bit(struct SliceData_t* self);
+- uint8_t SliceData_get_next_byte(struct SliceData_t* self);
++ void SliceData_move_by(struct SliceData_t* self, uint16_t offset);
++ uint8_t SliceData_get_bits(const struct SliceData_t* self, uint16_t offset, uint8_t bits);
++ uint8_t SliceData_get_next_bit(struct SliceData_t* self);
++ uint8_t SliceData_get_next_byte(struct SliceData_t* self);
+uint64_t SliceData_get_next_int(struct SliceData_t* self, uint8_t bits);
+uint64_t SliceData_get_next_size(struct SliceData_t* self, uint16_t max_value);
+- bool SliceData_is_empty(const struct SliceData_t* self);
+- bool SliceData_equal(const struct SliceData_t* self, const struct SliceData_t* other);
++ bool SliceData_is_empty(const struct SliceData_t* self);
++ bool SliceData_equal(const struct SliceData_t* self, const struct SliceData_t* other);
+uint16_t SliceData_get_cursor(const struct SliceData_t* self);
+uint8_t* SliceData_begin(const struct SliceData_t* self);
+uint16_t SliceData_data_size(const struct SliceData_t* self);
+- void SliceData_append(struct SliceData_t* self, uint8_t* data, uint16_t bits, bool append_tag);
++ void SliceData_append(struct SliceData_t* self, uint8_t* data, uint16_t bits, bool append_tag);
+
+#endif
+-- -./ src / globals.h(original)++ +./ src / globals.h(reformatted) @ @-46, 7 + 46,
+ 7 @ @ void reset_app_context(void);
+
+typedef struct BocContext_t {
+ - Cell_t cells[MAX_CONTRACT_CELLS_COUNT];
+ + Cell_t cells[MAX_CONTRACT_CELLS_COUNT];
+ uint8_t hashes[HASHES_BUFFER_SIZE];
+ uint8_t cell_depth[MAX_CONTRACT_CELLS_COUNT];
+ uint8_t public_key_cell_data[MAX_PUBLIC_KEY_CELL_DATA_SIZE];
+ @ @-57, 46 + 57,
+ 46 @ @
+
+ typedef struct AddressContext_t {
+ uint8_t address[ADDRESS_LENGTH];
+ - char address_str[65];
+ + char address_str[65];
+ } AddressContext_t;
+
+ typedef struct PublicKeyContext_t {
+ uint8_t public_key[PUBLIC_KEY_LENGTH];
+ - char public_key_str[65];
+ + char public_key_str[65];
+ } PublicKeyContext_t;
+
+ typedef struct SignContext_t {
+ - uint8_t chain_id[CHAIN_ID_LENGTH];
+ - uint8_t to_sign[SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH];
+ - uint8_t signature[SIGNATURE_LENGTH];
+ + uint8_t chain_id[CHAIN_ID_LENGTH];
+ + uint8_t to_sign[SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH];
+ + uint8_t signature[SIGNATURE_LENGTH];
+ uint32_t account_number;
+ - char to_sign_str[73];
+ + char to_sign_str[73];
+ } SignContext_t;
+
+ typedef struct SignTransactionContext_t {
+ - bool sign_with_chain_id;
+ - uint8_t chain_id[CHAIN_ID_LENGTH];
+ - uint8_t to_sign[CHAIN_ID_LENGTH + TO_SIGN_LENGTH];
+ - uint8_t signature[SIGNATURE_LENGTH];
+ - char address_str[70];
+ - char amount_str[40];
+ - char transaction_id_str[20];
+ + bool sign_with_chain_id;
+ + uint8_t chain_id[CHAIN_ID_LENGTH];
+ + uint8_t to_sign[CHAIN_ID_LENGTH + TO_SIGN_LENGTH];
+ + uint8_t signature[SIGNATURE_LENGTH];
+ + char address_str[70];
+ + char amount_str[40];
+ + char transaction_id_str[20];
+ uint32_t account_number;
+ - uint8_t origin_wallet_type;
+ - uint8_t current_wallet_type;
+ - uint8_t decimals;
+ - uint8_t address[ADDRESS_LENGTH];
+ - uint8_t prepend_address[ADDRESS_LENGTH];
+ - uint8_t wc;
+ - uint8_t data[MAX_DATA_LEN];
+ + uint8_t origin_wallet_type;
+ + uint8_t current_wallet_type;
+ + uint8_t decimals;
+ + uint8_t address[ADDRESS_LENGTH];
+ + uint8_t prepend_address[ADDRESS_LENGTH];
+ + uint8_t wc;
+ + uint8_t data[MAX_DATA_LEN];
+ uint16_t data_offset;
+ - char ticker[MAX_TICKER_LEN];
+ + char ticker[MAX_TICKER_LEN];
+ } SignTransactionContext_t;
+
+ typedef union {
+ - PublicKeyContext_t pk_context;
+ - AddressContext_t addr_context;
+ - SignContext_t sign_context;
+ + PublicKeyContext_t pk_context;
+ + AddressContext_t addr_context;
+ + SignContext_t sign_context;
+ SignTransactionContext_t sign_tr_context;
+ } DataContext_t;
+
+ @ @-104, 7 + 104, 7 @ @ extern unsigned int ux_step;
+ extern unsigned int ux_step_count;
+
+ - extern BocContext_t boc_context;
+ + extern BocContext_t boc_context;
+ extern DataContext_t data_context;
+
+#endif
+ -- -./ src / byte_stream.h(original)++ +./ src / byte_stream.h(reformatted) @ @-9, 9 + 9,
+ 9 @ @uint8_t* data;
+} ByteStream_t;
+
+- void ByteStream_init(struct ByteStream_t* self, uint8_t* data, uint16_t data_size);
++ void ByteStream_init(struct ByteStream_t* self, uint8_t* data, uint16_t data_size);
+uint8_t* ByteStream_read_data(struct ByteStream_t* self, uint32_t data_size);
+- uint8_t ByteStream_read_byte(struct ByteStream_t* self);
++ uint8_t ByteStream_read_byte(struct ByteStream_t* self);
+uint32_t ByteStream_read_u32(struct ByteStream_t* self);
+uint8_t* ByteStream_get_cursor(struct ByteStream_t* self);
+uint16_t ByteStream_get_length(struct ByteStream_t* self);
+-- -./ src / errors.h(original)++ +./ src / errors.h(reformatted) @ @-2, 28 + 2,
+ 28 @ @
+#define _ERRORS_H_
+
+ enum {
+ -SUCCESS = 0x9000,
+ -ERR_INVALID_DATA = 0x6B00,
+ -ERR_CELL_UNDERFLOW = 0x6B01,
+ -ERR_RANGE_CHECK = 0x6B02,
+ -ERR_WRONG_LABEL = 0x6B03,
+ -ERR_INVALID_FLAG = 0x6B04,
+ -ERR_END_OF_STREAM = 0x6B05,
+ -ERR_SLICE_IS_EMPTY = 0x6B06,
+ -ERR_INVALID_KEY = 0x6B07,
+ -ERR_CELL_IS_EMPTY = 0x6B08,
+ -ERR_INVALID_HASH = 0x6B09,
+ -ERR_INVALID_CELL_INDEX = 0x6B10,
+ -ERR_INVALID_REQUEST = 0x6B11,
+ +SUCCESS = 0x9000,
+ +ERR_INVALID_DATA = 0x6B00,
+ +ERR_CELL_UNDERFLOW = 0x6B01,
+ +ERR_RANGE_CHECK = 0x6B02,
+ +ERR_WRONG_LABEL = 0x6B03,
+ +ERR_INVALID_FLAG = 0x6B04,
+ +ERR_END_OF_STREAM = 0x6B05,
+ +ERR_SLICE_IS_EMPTY = 0x6B06,
+ +ERR_INVALID_KEY = 0x6B07,
+ +ERR_CELL_IS_EMPTY = 0x6B08,
+ +ERR_INVALID_HASH = 0x6B09,
+ +ERR_INVALID_CELL_INDEX = 0x6B10,
+ +ERR_INVALID_REQUEST = 0x6B11,
+ ERR_INVALID_FUNCTION_ID = 0x6B12,
+ ERR_INVALID_SRC_ADDRESS = 0x6B13,
+ -ERR_INVALID_WALLET_ID = 0x6B14,
+ +ERR_INVALID_WALLET_ID = 0x6B14,
+ ERR_INVALID_WALLET_TYPE = 0x6B15,
+ -ERR_TICKER_LENGTH = 0x6B16,
+ -ERR_INVALID_CELL = 0x6B17,
+ -ERR_INVALID_CONTRACT = 0x6B18,
+ -ERR_INVALID_MESSAGE = 0x6B19,
+ -ERR_SIGNING_FAILED = 0x6B20,
+ +ERR_TICKER_LENGTH = 0x6B16,
+ +ERR_INVALID_CELL = 0x6B17,
+ +ERR_INVALID_CONTRACT = 0x6B18,
+ +ERR_INVALID_MESSAGE = 0x6B19,
+ +ERR_SIGNING_FAILED = 0x6B20,
+ ERR_GENERATE_PAIR_FAILED = 0x6B21,
+ ERR_INIT_PRIVATE_KEY_FAILED = 0x6B22,
+ ERR_DERIVE_PATH_FAILED = 0x6B23,
+ -- -./ src / utils.h(original)++ +./ src / utils.h(reformatted) @ @-10,
+ 26 + 10,
+ 26 @ @
+
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+
+ -unsigned int ui_prepro(const bagl_element_t* element);
+ -void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray);
+ -void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey);
+ -void send_response(uint8_t tx, bool approve);
+ +unsigned int ui_prepro(const bagl_element_t* element);
+ +void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray);
+ +void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey);
+ +void send_response(uint8_t tx, bool approve);
+
+#endif
+
+ -void writeUint32BE(uint32_t val, uint8_t* bytes);
+ -void writeUint64BE(uint64_t val, uint8_t* bytes);
+ +void writeUint32BE(uint32_t val, uint8_t* bytes);
+ +void writeUint64BE(uint64_t val, uint8_t* bytes);
+
+ -uint16_t readUint16BE(uint8_t * buffer);
+ -uint32_t readUint32BE(uint8_t * buffer);
+ -uint64_t readUint64BE(uint8_t * buffer);
+ -uint8_t leading_zeros(uint16_t value);
+ +uint16_t readUint16BE(uint8_t * buffer);
+ +uint32_t readUint32BE(uint8_t * buffer);
+ +uint64_t readUint64BE(uint8_t * buffer);
+ +uint8_t leading_zeros(uint16_t value);
+
+ -uint16_t format_hex(const uint8_t* in, size_t in_len, char* out, size_t out_len);
+ -uint8_t convert_hex_amount_to_displayable(const uint8_t* amount,
+ -uint8_t decimals,
+ -uint8_t amount_length,
+ -char* out);
+ +uint16_t format_hex(const uint8_t* in, size_t in_len, char* out, size_t out_len);
+ +uint8_t convert_hex_amount_to_displayable(const uint8_t* amount,
+ +uint8_t decimals,
+ +uint8_t amount_length,
+ +char* out);
+
+#define VALIDATE(cond, error) do {
\ No newline at end of file
diff --git a/src/ui/action/validate.c b/src/ui/action/validate.c
new file mode 100644
index 0000000..71e9a2a
--- /dev/null
+++ b/src/ui/action/validate.c
@@ -0,0 +1,116 @@
+/*****************************************************************************
+ * Ledger App Everscale.
+ * (c) 2020 Ledger SAS.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *****************************************************************************/
+
+#include "io.h"
+#include "validate.h"
+#include "errors.h"
+#include "globals.h"
+#include "utils.h"
+#include "helper/send_response.h"
+
+void validate_pubkey(bool choice) {
+ if (choice) {
+ helper_send_response_public_key();
+ } else {
+ io_send_sw(ERR_USER_REJECTED);
+ }
+}
+
+void validate_address(bool choice) {
+ if (choice) {
+ helper_send_response_address();
+ } else {
+ io_send_sw(ERR_USER_REJECTED);
+ }
+}
+
+static int crypto_sign_message(void) {
+ cx_ecfp_private_key_t privateKey;
+ SignContext_t* context = &data_context.sign_context;
+ cx_err_t error;
+
+ if (get_private_key(context->account_number, &privateKey) != 0) {
+ return -1;
+ }
+ error = cx_eddsa_sign_no_throw(&privateKey,
+ CX_SHA512,
+ context->to_sign,
+ SIGN_MAGIC_LENGTH + TO_SIGN_LENGTH,
+ context->signature,
+ SIGNATURE_LENGTH);
+ if (error != CX_OK) {
+ return -2;
+ }
+
+ explicit_bzero(&privateKey, sizeof(privateKey));
+ PRINTF("Signature: %.*H\n", SIGNATURE_LENGTH, context->signature);
+ return 0;
+}
+
+void validate_message(bool choice) {
+ if (choice) {
+ if (crypto_sign_message() != 0) {
+ io_send_sw(ERR_SIGNING_FAILED);
+ } else {
+ helper_send_response_sign();
+ }
+ } else {
+ io_send_sw(ERR_USER_REJECTED);
+ }
+}
+
+static int crypto_sign_transaction(void) {
+ cx_ecfp_private_key_t privateKey;
+ SignTransactionContext_t* context = &data_context.sign_tr_context;
+ cx_err_t error;
+
+ if (get_private_key(context->account_number, &privateKey) != 0) {
+ return -1;
+ }
+ if (!context->sign_with_chain_id) {
+ error = cx_eddsa_sign_no_throw(&privateKey,
+ CX_SHA512,
+ context->to_sign,
+ TO_SIGN_LENGTH,
+ context->signature,
+ SIGNATURE_LENGTH);
+ } else {
+ error = cx_eddsa_sign_no_throw(&privateKey,
+ CX_SHA512,
+ context->to_sign,
+ CHAIN_ID_LENGTH + TO_SIGN_LENGTH,
+ context->signature,
+ SIGNATURE_LENGTH);
+ }
+ if (error != CX_OK) {
+ return -2;
+ }
+ explicit_bzero(&privateKey, sizeof(privateKey));
+ return 0;
+}
+
+void validate_transaction(bool choice) {
+ if (choice) {
+ if (crypto_sign_transaction() != 0) {
+ io_send_sw(ERR_SIGNING_FAILED);
+ } else {
+ helper_send_response_sign_transaction();
+ }
+ } else {
+ io_send_sw(ERR_USER_REJECTED);
+ }
+}
\ No newline at end of file
diff --git a/src/ui/action/validate.h b/src/ui/action/validate.h
new file mode 100644
index 0000000..f835f80
--- /dev/null
+++ b/src/ui/action/validate.h
@@ -0,0 +1,36 @@
+#pragma once
+
+#include // bool
+
+/**
+ * Action for public key validation and export.
+ *
+ * @param[in] choice
+ * User choice (either approved or rejected).
+ *
+ */
+void validate_pubkey(bool choice);
+
+/**
+ * Action for address validation and export.
+ *
+ * @param[in] choice
+ * User choice (either approved or rejectd).
+ *
+ */
+void validate_address(bool choice);
+/**
+ * Action for transaction information validation.
+ *
+ * @param[in] choice
+ * User choice (either approved or rejectd).
+ *
+ */
+void validate_transaction(bool choice);
+
+/**
+ * Action for sign validation.
+ *
+ * @param[in] choice
+ */
+void validate_message(bool choice);
\ No newline at end of file
diff --git a/src/ui/display.h b/src/ui/display.h
new file mode 100644
index 0000000..edcf3a2
--- /dev/null
+++ b/src/ui/display.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include // bool
+
+/**
+ * Callback to reuse action with approve/reject in step FLOW.
+ */
+typedef void (*action_validate_cb)(bool);
+
+void ui_display_address();
+void ui_display_public_key();
+void ui_display_sign_transaction(int flow);
+void ui_display_sign();
diff --git a/src/ui/display_bagl.c b/src/ui/display_bagl.c
new file mode 100644
index 0000000..f089265
--- /dev/null
+++ b/src/ui/display_bagl.c
@@ -0,0 +1,214 @@
+#ifdef HAVE_BAGL
+#include "display.h"
+#include "contract.h"
+#include "ui/action/validate.h"
+#include "ui/menu.h"
+
+static action_validate_cb g_validate_callback;
+
+static void ui_action_validate_pubkey(bool choice) {
+ validate_pubkey(choice);
+ ui_main_menu();
+}
+
+static void ui_action_validate_address(bool choice) {
+ validate_address(choice);
+ ui_main_menu();
+}
+
+static void ui_action_validate_message(bool choice) {
+ validate_message(choice);
+ ui_main_menu();
+}
+
+static void ui_action_validate_transaction(bool choice) {
+ validate_transaction(choice);
+ ui_main_menu();
+}
+
+// Screens and flows
+UX_STEP_NOCB(ux_display_address_flow_1_step,
+ pnn,
+ {
+ &C_icon_eye,
+ "Verify",
+ "address",
+ });
+UX_STEP_NOCB(ux_display_address_flow_2_step,
+ bnnn_paging,
+ {
+ .title = "Address",
+ .text = data_context.addr_context.address_str,
+ });
+UX_STEP_CB(ux_display_reject_step,
+ pb,
+ (*g_validate_callback)(false),
+ {
+ &C_icon_crossmark,
+ "Reject",
+ });
+UX_STEP_CB(ux_display_approve_step,
+ pb,
+ (*g_validate_callback)(true),
+ {
+ &C_icon_validate_14,
+ "Approve",
+ });
+
+UX_FLOW(ux_display_address_flow,
+ &ux_display_address_flow_1_step,
+ &ux_display_address_flow_2_step,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+UX_STEP_NOCB(ux_display_public_flow_1_step,
+ pnn,
+ {
+ &C_icon_eye,
+ "Verify",
+ "Public key",
+ });
+UX_STEP_NOCB(ux_display_public_flow_2_step,
+ bnnn_paging,
+ {
+ .title = "Public key",
+ .text = data_context.pk_context.public_key_str,
+ });
+
+UX_FLOW(ux_display_public_flow,
+ &ux_display_public_flow_1_step,
+ &ux_display_public_flow_2_step,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+UX_STEP_NOCB(ux_sign_flow_1_step,
+ pnn,
+ {
+ &C_icon_certificate,
+ "Sign",
+ "message",
+ });
+UX_STEP_NOCB(ux_sign_flow_2_step,
+ bnnn_paging,
+ {
+ .title = "Message",
+ .text = data_context.sign_context.to_sign_str,
+ });
+UX_STEP_CB(ux_sign_flow_4_step,
+ pbb,
+ (*g_validate_callback)(false),
+ {
+ &C_icon_crossmark,
+ "Cancel",
+ "signature",
+ });
+UX_STEP_CB(ux_sign_flow_3_step,
+ pbb,
+ (*g_validate_callback)(true),
+ {
+ &C_icon_validate_14,
+ "Sign",
+ "message.",
+ });
+
+UX_FLOW(ux_sign_flow,
+ &ux_sign_flow_1_step,
+ &ux_sign_flow_2_step,
+ &ux_sign_flow_3_step,
+ &ux_sign_flow_4_step);
+
+UX_STEP_NOCB(ux_sign_transaction_intro,
+ pnn,
+ {
+ &C_icon_eye,
+ "Review",
+ "transaction",
+ });
+UX_STEP_NOCB(ux_sign_transaction_burn, bnnn_paging, {.title = "Action", .text = "Burn"});
+UX_STEP_NOCB(ux_sign_transaction_deploy, bnnn_paging, {.title = "Action", .text = "Deploy"});
+UX_STEP_NOCB(ux_sign_transaction_confirm, bnnn_paging, {.title = "Action", .text = "Confirm"});
+UX_STEP_NOCB(ux_sign_transaction_transfer, bnnn_paging, {.title = "Action", .text = "Transfer"});
+UX_STEP_NOCB(ux_sign_transaction_amount,
+ bnnn_paging,
+ {
+ .title = "Amount",
+ .text = data_context.sign_tr_context.amount_str,
+ });
+UX_STEP_NOCB(ux_sign_transaction_address,
+ bnnn_paging,
+ {
+ .title = "Address",
+ .text = data_context.sign_tr_context.address_str,
+ });
+UX_STEP_NOCB(ux_sign_transaction_transaction_id,
+ bnnn_paging,
+ {
+ .title = "Transaction id",
+ .text = data_context.sign_tr_context.transaction_id_str,
+ });
+
+UX_FLOW(ux_sign_transaction_burn_flow,
+ &ux_sign_transaction_intro,
+ &ux_sign_transaction_burn,
+ &ux_sign_transaction_amount,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+UX_FLOW(ux_sign_transaction_deploy_flow,
+ &ux_sign_transaction_intro,
+ &ux_sign_transaction_deploy,
+ &ux_sign_transaction_address,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+UX_FLOW(ux_sign_transaction_confirm_flow,
+ &ux_sign_transaction_intro,
+ &ux_sign_transaction_confirm,
+ &ux_sign_transaction_transaction_id,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+UX_FLOW(ux_sign_transaction_transfer_flow,
+ &ux_sign_transaction_intro,
+ &ux_sign_transaction_transfer,
+ &ux_sign_transaction_amount,
+ &ux_sign_transaction_address,
+ &ux_display_approve_step,
+ &ux_display_reject_step);
+
+// Display functions
+void ui_display_address() {
+ g_validate_callback = &ui_action_validate_address;
+ ux_flow_init(0, ux_display_address_flow, NULL);
+}
+
+void ui_display_public_key() {
+ g_validate_callback = &ui_action_validate_pubkey;
+ ux_flow_init(0, ux_display_public_flow, NULL);
+}
+
+void ui_display_sign() {
+ g_validate_callback = &ui_action_validate_message;
+ ux_flow_init(0, ux_sign_flow, NULL);
+}
+
+void ui_display_sign_transaction(int flow) {
+ g_validate_callback = &ui_action_validate_transaction;
+ switch (flow) {
+ case SIGN_TRANSACTION_FLOW_TRANSFER:
+ ux_flow_init(0, ux_sign_transaction_transfer_flow, NULL);
+ break;
+ case SIGN_TRANSACTION_FLOW_DEPLOY:
+ ux_flow_init(0, ux_sign_transaction_deploy_flow, NULL);
+ break;
+ case SIGN_TRANSACTION_FLOW_CONFIRM:
+ ux_flow_init(0, ux_sign_transaction_confirm_flow, NULL);
+ break;
+ case SIGN_TRANSACTION_FLOW_BURN:
+ ux_flow_init(0, ux_sign_transaction_burn_flow, NULL);
+ break;
+ default:
+ THROW(ERR_INVALID_REQUEST);
+ }
+}
+#endif
\ No newline at end of file
diff --git a/src/ui/display_nbgl.c b/src/ui/display_nbgl.c
new file mode 100644
index 0000000..5f810af
--- /dev/null
+++ b/src/ui/display_nbgl.c
@@ -0,0 +1,181 @@
+#ifdef HAVE_NBGL
+#include "display.h"
+#include "contract.h"
+#include "ui/action/validate.h"
+#include "ui/menu.h"
+#include "nbgl_use_case.h"
+
+static nbgl_contentTagValue_t pairs[10];
+static nbgl_contentTagValueList_t pairList;
+
+static void review_choice_pubkey(bool choice) {
+ // Answer, display a status page and go back to main
+ validate_pubkey(choice);
+ if (choice) {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_main_menu);
+ } else {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_main_menu);
+ }
+}
+
+static void review_choice_address(bool choice) {
+ // Answer, display a status page and go back to main
+ validate_address(choice);
+ if (choice) {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_VERIFIED, ui_main_menu);
+ } else {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_ADDRESS_REJECTED, ui_main_menu);
+ }
+}
+
+static void review_choice_transaction(bool choice) {
+ // Answer, display a status page and go back to main
+ validate_transaction(choice);
+ if (choice) {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_SIGNED, ui_main_menu);
+ } else {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_TRANSACTION_REJECTED, ui_main_menu);
+ }
+}
+
+static void review_choice_message(bool choice) {
+ // Answer, display a status page and go back to main
+ validate_message(choice);
+ if (choice) {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_SIGNED, ui_main_menu);
+ } else {
+ nbgl_useCaseReviewStatus(STATUS_TYPE_MESSAGE_REJECTED, ui_main_menu);
+ }
+}
+
+// TODO: Implement this
+void ui_display_address() {
+ nbgl_useCaseAddressReview(data_context.addr_context.address_str,
+ NULL,
+ &C_app_everscale_64px,
+ "Verify Address",
+ NULL,
+ review_choice_address);
+}
+
+// TODO: Implement this
+void ui_display_public_key() {
+ // Create the page content
+
+ uint8_t pairIndex = 0;
+ pairs[pairIndex].item = "Public Key";
+ pairs[pairIndex].value = (char*) data_context.pk_context.public_key_str;
+ pairIndex++;
+
+ nbgl_contentTagValueList_t content;
+ content.nbPairs = pairIndex;
+ content.pairs = pairs;
+ content.smallCaseForValue = false;
+ content.nbMaxLinesForValue = 0;
+ content.startIndex = 0;
+
+ // to signing screens.
+ // Setup the review screen
+ nbgl_useCaseReviewLight(TYPE_OPERATION,
+ &content,
+ &C_app_everscale_64px,
+ "Verify Public Key",
+ NULL, // No subtitle
+ "Approve",
+ review_choice_pubkey);
+
+ // nbgl_useCaseAddressReview(data_context.pk_context.public_key_str,
+ // NULL,
+ // &C_app_everscale_40px,
+ // "Verify Public Key",
+ // NULL,
+ // review_choice_pubkey);
+}
+
+void ui_display_sign_transaction(int flow) {
+ uint8_t pairIndex = 0;
+
+ // Action line
+ const char* action = NULL;
+ switch (flow) {
+ case SIGN_TRANSACTION_FLOW_TRANSFER:
+ action = "Transfer";
+ break;
+ case SIGN_TRANSACTION_FLOW_DEPLOY:
+ action = "Deploy";
+ break;
+ case SIGN_TRANSACTION_FLOW_CONFIRM:
+ action = "Confirm";
+ break;
+ case SIGN_TRANSACTION_FLOW_BURN:
+ action = "Burn";
+ break;
+ default:
+ THROW(ERR_INVALID_REQUEST);
+ break;
+ }
+ pairs[pairIndex].item = "Action";
+ pairs[pairIndex].value = action;
+ pairIndex++;
+
+ // Amount line
+ if (strcmp(action, "Transfer") == 0 || strcmp(action, "Burn") == 0) {
+ pairs[pairIndex].item = "Amount";
+ pairs[pairIndex].value = (char*) data_context.sign_tr_context.amount_str;
+ pairIndex++;
+ }
+
+ // Address line
+ if (strcmp(action, "Transfer") == 0 || strcmp(action, "Deploy") == 0) {
+ pairs[pairIndex].item = "Address";
+ pairs[pairIndex].value = (char*) data_context.sign_tr_context.address_str;
+ pairIndex++;
+ }
+
+ // Transaction id line
+ if (strcmp(action, "Confirm") == 0) {
+ pairs[pairIndex].item = "Transaction id";
+ pairs[pairIndex].value = (char*) data_context.sign_tr_context.transaction_id_str;
+ pairIndex++;
+ }
+
+ // Setup list
+ pairList.nbMaxLinesForValue = 0;
+ pairList.nbPairs = pairIndex;
+ pairList.pairs = pairs;
+
+ // to signing screens.
+ // Setup the review screen
+ nbgl_useCaseReview(TYPE_TRANSACTION,
+ &pairList,
+ &C_app_everscale_64px,
+ "Review transaction",
+ NULL, // No subtitle
+ "Review transaction",
+ review_choice_transaction);
+}
+
+void ui_display_sign() {
+ uint8_t pairIndex = 0;
+
+ pairs[pairIndex].item = "Message";
+ pairs[pairIndex].value = data_context.sign_context.to_sign_str;
+ pairIndex++;
+
+ // Setup list
+ pairList.nbMaxLinesForValue = 0;
+ pairList.nbPairs = pairIndex;
+ pairList.pairs = pairs;
+
+ // to signing screens.
+ // Setup the review screen
+ nbgl_useCaseReview(TYPE_MESSAGE,
+ &pairList,
+ &C_app_everscale_64px,
+ "Sign message",
+ NULL, // No subtitle
+ "Sign message.",
+ review_choice_message);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/ui/menu.h b/src/ui/menu.h
new file mode 100644
index 0000000..aa15b48
--- /dev/null
+++ b/src/ui/menu.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include "globals.h"
+#include "glyphs.h"
+
+void ui_main_menu(void);
+
+void ui_about_menu(void);
diff --git a/src/ui/menu_bagl.c b/src/ui/menu_bagl.c
new file mode 100644
index 0000000..e33faa7
--- /dev/null
+++ b/src/ui/menu_bagl.c
@@ -0,0 +1,34 @@
+#ifdef HAVE_BAGL
+#include "menu.h"
+#include "os.h"
+
+//////////////////////////////////////////////////////////////////////
+UX_STEP_NOCB(ux_idle_flow_1_step,
+ nn,
+ {
+ "Application",
+ "is ready",
+ });
+UX_STEP_NOCB(ux_idle_flow_3_step,
+ bn,
+ {
+ "Version",
+ APPVERSION,
+ });
+UX_STEP_VALID(ux_idle_flow_4_step,
+ pb,
+ os_sched_exit(-1),
+ {
+ &C_icon_dashboard_x,
+ "Quit",
+ });
+UX_FLOW(ux_idle_flow, &ux_idle_flow_1_step, &ux_idle_flow_3_step, &ux_idle_flow_4_step, FLOW_LOOP);
+
+void ui_main_menu(void) {
+ // reserve a display stack slot if none yet
+ if (G_ux.stack_count == 0) {
+ ux_stack_push();
+ }
+ ux_flow_init(0, ux_idle_flow, NULL);
+}
+#endif
diff --git a/src/ui/menu_nbgl.c b/src/ui/menu_nbgl.c
new file mode 100644
index 0000000..d78643f
--- /dev/null
+++ b/src/ui/menu_nbgl.c
@@ -0,0 +1,39 @@
+#ifdef HAVE_NBGL
+
+#include "os.h"
+#include "nbgl_content.h"
+#include "nbgl_use_case.h"
+#include "menu.h"
+
+// -----------------------------------------------------------
+// --------------------- SETTINGS MENU -----------------------
+// -----------------------------------------------------------
+#define SETTING_INFO_NB 2
+static const char* const INFO_TYPES[SETTING_INFO_NB] = {"Version", "Developer"};
+static const char* const INFO_CONTENTS[SETTING_INFO_NB] = {APPVERSION, "Blooo"};
+static const nbgl_contentInfoList_t infoList = {
+ .nbInfos = SETTING_INFO_NB,
+ .infoTypes = INFO_TYPES,
+ .infoContents = INFO_CONTENTS,
+};
+
+// -----------------------------------------------------------
+// ----------------------- HOME PAGE -------------------------
+// -----------------------------------------------------------
+void app_quit(void) {
+ // exit app here
+ os_sched_exit(-1);
+}
+
+void ui_main_menu(void) {
+ nbgl_useCaseHomeAndSettings(APPNAME,
+ &C_app_everscale_64px,
+ NULL,
+ INIT_HOME_PAGE,
+ NULL,
+ &infoList,
+ NULL,
+ app_quit);
+}
+
+#endif
\ No newline at end of file
diff --git a/src/utils.c b/src/utils.c
index 598b4b9..d8868b1 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1,30 +1,20 @@
-#include "os.h"
-#include "cx.h"
#include "utils.h"
-#include "menu.h"
#include
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-void get_public_key(uint32_t account_number, uint8_t* publicKeyArray) {
+int get_public_key(uint32_t account_number, uint8_t* publicKeyArray) {
cx_ecfp_private_key_t privateKey;
cx_ecfp_public_key_t publicKey;
-
- get_private_key(account_number, &privateKey);
- BEGIN_TRY {
- TRY {
- cx_ecfp_generate_pair(CX_CURVE_Ed25519, &publicKey, &privateKey, 1);
- }
- CATCH_OTHER(e) {
- explicit_bzero(&privateKey, sizeof(privateKey));
- THROW(e);
- }
- FINALLY {
- explicit_bzero(&privateKey, sizeof(privateKey));
- }
+ if (get_private_key(account_number, &privateKey) != 0) {
+ return -1;
+ }
+ cx_err_t error = cx_ecfp_generate_pair_no_throw(CX_CURVE_Ed25519, &publicKey, &privateKey, 1);
+ if (error != CX_OK) {
+ return -2;
}
- END_TRY;
+ explicit_bzero(&privateKey, sizeof(privateKey));
for (int i = 0; i < 32; i++) {
publicKeyArray[i] = publicKey.W[64 - i];
@@ -32,82 +22,58 @@ void get_public_key(uint32_t account_number, uint8_t* publicKeyArray) {
if ((publicKey.W[32] & 1) != 0) {
publicKeyArray[31] |= 0x80;
}
+ return 0;
}
static const uint32_t HARDENED_OFFSET = 0x80000000;
-void get_private_key(uint32_t account_number, cx_ecfp_private_key_t *privateKey) {
- const uint32_t derivePath[BIP32_PATH] = {
- 44 | HARDENED_OFFSET,
- 396 | HARDENED_OFFSET,
- account_number | HARDENED_OFFSET,
- 0 | HARDENED_OFFSET,
- 0 | HARDENED_OFFSET
- };
-
- uint8_t privateKeyData[32];
- BEGIN_TRY {
- TRY {
- os_perso_derive_node_bip32_seed_key(HDW_ED25519_SLIP10,
- CX_CURVE_Ed25519,
- derivePath,
- BIP32_PATH,
- privateKeyData,
- NULL,
- NULL,
- 0);
- cx_ecfp_init_private_key(CX_CURVE_Ed25519,
- privateKeyData,
- 32,
- privateKey);
- }
- CATCH_OTHER(e) {
- explicit_bzero(&privateKeyData, sizeof(privateKeyData));
- THROW(e);
- }
- FINALLY {
- explicit_bzero(&privateKeyData, sizeof(privateKeyData));
- }
+/**
+ * @brief Get the private key object
+ *
+ * @param account_number
+ * @param privateKey
+ * @return 0 on success, -1 on error
+ */
+int get_private_key(uint32_t account_number, cx_ecfp_private_key_t* privateKey) {
+ const uint32_t derivePath[BIP32_PATH] = {44 | HARDENED_OFFSET,
+ 396 | HARDENED_OFFSET,
+ account_number | HARDENED_OFFSET,
+ 0 | HARDENED_OFFSET,
+ 0 | HARDENED_OFFSET};
+
+ uint8_t privateKeyData[64];
+ if (os_derive_bip32_with_seed_no_throw(HDW_ED25519_SLIP10,
+ CX_CURVE_Ed25519,
+ derivePath,
+ BIP32_PATH,
+ privateKeyData,
+ NULL,
+ NULL,
+ 0) != CX_OK) {
+ return -1;
}
- END_TRY;
-}
+ cx_err_t error =
+ cx_ecfp_init_private_key_no_throw(CX_CURVE_Ed25519, privateKeyData, 32, privateKey);
-void send_response(uint8_t tx, bool approve) {
- G_io_apdu_buffer[tx++] = approve? 0x90 : 0x69;
- G_io_apdu_buffer[tx++] = approve? 0x00 : 0x85;
- reset_app_context();
- // Send back the response, do not restart the event loop
- io_exchange(CHANNEL_APDU | IO_RETURN_AFTER_TX, tx);
- // Display back the original UX
- ui_idle();
-}
+ explicit_bzero(&privateKeyData, sizeof(privateKeyData));
-unsigned int ui_prepro(const bagl_element_t *element) {
- unsigned int display = 1;
- if (element->component.userid > 0) {
- display = (ux_step == element->component.userid - 1);
- if (display) {
- if (element->component.userid == 1) {
- UX_CALLBACK_SET_INTERVAL(2000);
- }
- else {
- UX_CALLBACK_SET_INTERVAL(MAX(3000, 1000 + bagl_label_roundtrip_duration_ms(element, 7)));
- }
- }
+ if (error != CX_OK) {
+ return -1;
}
- return display;
+
+ return 0;
}
#endif
-void writeUint32BE(uint32_t val, uint8_t *bytes) {
+void writeUint32BE(uint32_t val, uint8_t* bytes) {
bytes[0] = (val >> 24) & 0xFF;
bytes[1] = (val >> 16) & 0xFF;
bytes[2] = (val >> 8) & 0xFF;
bytes[3] = val & 0xFF;
}
-void writeUint64BE(uint64_t val, uint8_t *bytes) {
+void writeUint64BE(uint64_t val, uint8_t* bytes) {
bytes[0] = (val >> 56) & 0xFF;
bytes[1] = (val >> 48) & 0xFF;
bytes[2] = (val >> 40) & 0xFF;
@@ -118,15 +84,15 @@ void writeUint64BE(uint64_t val, uint8_t *bytes) {
bytes[7] = val & 0xFF;
}
-uint16_t readUint16BE(uint8_t *buffer) {
+uint16_t readUint16BE(uint8_t* buffer) {
return (buffer[0] << 8) | (buffer[1]);
}
-uint32_t readUint32BE(uint8_t *buffer) {
+uint32_t readUint32BE(uint8_t* buffer) {
return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
}
-uint64_t readUint64BE(uint8_t *buffer) {
+uint64_t readUint64BE(uint8_t* buffer) {
uint32_t i1 = buffer[3] + (buffer[2] << 8u) + (buffer[1] << 16u) + (buffer[0] << 24u);
uint32_t i2 = buffer[7] + (buffer[6] << 8u) + (buffer[5] << 16u) + (buffer[4] << 24u);
return i2 | ((uint64_t) i1 << 32u);
@@ -145,35 +111,11 @@ uint8_t leading_zeros(uint16_t value) {
return lz;
}
-uint16_t format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len) {
- if (out_len < 2 * in_len + 1) {
- return -1;
- }
-
- const char hex[] = "0123456789abcdef";
- size_t i = 0;
- int written = 0;
-
- while (i < in_len && (i * 2 + (2 + 1)) <= out_len) {
- uint8_t high_nibble = (in[i] & 0xF0) >> 4;
- *out = hex[high_nibble];
- out++;
-
- uint8_t low_nibble = in[i] & 0x0F;
- *out = hex[low_nibble];
- out++;
-
- i++;
- written += 2;
- }
-
- *out = '\0';
-
- return written + 1;
-}
-
#define SCRATCH_SIZE 37
-uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimals, uint8_t amount_length, char* out) {
+uint8_t convert_hex_amount_to_displayable(const uint8_t* amount,
+ uint8_t decimals,
+ uint8_t amount_length,
+ char* out) {
uint8_t LOOP1 = SCRATCH_SIZE - decimals;
uint8_t LOOP2 = decimals;
uint16_t scratch[SCRATCH_SIZE];
@@ -194,8 +136,7 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal
for (j = 0; j < 8; j++) {
uint8_t k;
uint16_t shifted_in =
- (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short)1
- : (short)0;
+ (((amount[i] & 0xff) & ((1 << (7 - j)))) != 0) ? (short) 1 : (short) 0;
for (k = smin; k < nscratch; k++) {
scratch[k] += ((scratch[k] >= 5) ? 3 : 0);
}
@@ -204,11 +145,10 @@ uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimal
smin -= 1;
}
for (k = smin; k < nscratch - 1; k++) {
- scratch[k] =
- ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0);
+ scratch[k] = ((scratch[k] << 1) & 0xF) | ((scratch[k + 1] >= 8) ? 1 : 0);
}
- scratch[nscratch - 1] = ((scratch[nscratch - 1] << 1) & 0x0F) |
- (shifted_in == 1 ? 1 : 0);
+ scratch[nscratch - 1] =
+ ((scratch[nscratch - 1] << 1) & 0x0F) | (shifted_in == 1 ? 1 : 0);
}
}
diff --git a/src/utils.h b/src/utils.h
index de58385..be9306d 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -2,7 +2,6 @@
#define _UTILS_H_
#include "os.h"
-#include "cx.h"
#include "globals.h"
#include
@@ -10,31 +9,33 @@
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
-unsigned int ui_prepro(const bagl_element_t *element);
-void get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray);
-void get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t *privateKey);
-void send_response(uint8_t tx, bool approve);
+#include "cx.h"
+
+int get_public_key(uint32_t accountNumber, uint8_t* publicKeyArray);
+int get_private_key(uint32_t accountNumber, cx_ecfp_private_key_t* privateKey);
#endif
-void writeUint32BE(uint32_t val, uint8_t *bytes);
-void writeUint64BE(uint64_t val, uint8_t *bytes);
+void writeUint32BE(uint32_t val, uint8_t* bytes);
+void writeUint64BE(uint64_t val, uint8_t* bytes);
-uint16_t readUint16BE(uint8_t *buffer);
-uint32_t readUint32BE(uint8_t *buffer);
-uint64_t readUint64BE(uint8_t *buffer);
+uint16_t readUint16BE(uint8_t* buffer);
+uint32_t readUint32BE(uint8_t* buffer);
+uint64_t readUint64BE(uint8_t* buffer);
uint8_t leading_zeros(uint16_t value);
-uint16_t format_hex(const uint8_t *in, size_t in_len, char *out, size_t out_len);
-uint8_t convert_hex_amount_to_displayable(const uint8_t* amount, uint8_t decimals, uint8_t amount_length, char* out);
+uint8_t convert_hex_amount_to_displayable(const uint8_t* amount,
+ uint8_t decimals,
+ uint8_t amount_length,
+ char* out);
-#define VALIDATE(cond, error) \
- do {\
- if (!(cond)) { \
+#define VALIDATE(cond, error) \
+ do { \
+ if (!(cond)) { \
PRINTF("Validation Error in %s: %d\n", __FILE__, __LINE__); \
- THROW(error); \
- } \
- } while(0)
+ THROW(error); \
+ } \
+ } while (0)
#define PRINT_LINE() PRINTF("Print line %s: %d\n", __FILE__, __LINE__)
diff --git a/tests/.gitignore b/tests/.gitignore
deleted file mode 100644
index b83d222..0000000
--- a/tests/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/target/
diff --git a/tests/Cargo.lock b/tests/Cargo.lock
deleted file mode 100644
index 8bb05ac..0000000
--- a/tests/Cargo.lock
+++ /dev/null
@@ -1,2097 +0,0 @@
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "addr2line"
-version = "0.21.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
-
-[[package]]
-name = "aead"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
-dependencies = [
- "crypto-common",
- "generic-array",
-]
-
-[[package]]
-name = "ahash"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
-dependencies = [
- "getrandom",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "ahash"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
-dependencies = [
- "cfg-if",
- "getrandom",
- "once_cell",
- "version_check",
-]
-
-[[package]]
-name = "anstream"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
-dependencies = [
- "anstyle",
- "anstyle-parse",
- "anstyle-query",
- "anstyle-wincon",
- "colorchoice",
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
-
-[[package]]
-name = "anstyle-parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
-dependencies = [
- "utf8parse",
-]
-
-[[package]]
-name = "anstyle-query"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
-dependencies = [
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "anstyle-wincon"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
-dependencies = [
- "anstyle",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "anyhow"
-version = "1.0.75"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
-
-[[package]]
-name = "arrayref"
-version = "0.3.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
-
-[[package]]
-name = "arrayvec"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
-
-[[package]]
-name = "async-trait"
-version = "0.1.73"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "autocfg"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
-
-[[package]]
-name = "backtrace"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
-dependencies = [
- "addr2line",
- "cc",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
-]
-
-[[package]]
-name = "base58"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83"
-
-[[package]]
-name = "base64"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
-
-[[package]]
-name = "base64"
-version = "0.21.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
-
-[[package]]
-name = "base64ct"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b"
-
-[[package]]
-name = "bigdecimal"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "454bca3db10617b88b566f205ed190aedb0e0e6dd4cad61d3988a72e8c5594cb"
-dependencies = [
- "autocfg",
- "libm",
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "bitflags"
-version = "1.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
-
-[[package]]
-name = "bitflags"
-version = "2.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
-
-[[package]]
-name = "bitvec"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
-dependencies = [
- "funty",
- "radium",
- "tap",
- "wyz",
-]
-
-[[package]]
-name = "block-buffer"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "borsh"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
-dependencies = [
- "borsh-derive",
- "hashbrown 0.13.2",
-]
-
-[[package]]
-name = "borsh-derive"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
-dependencies = [
- "borsh-derive-internal",
- "borsh-schema-derive-internal",
- "proc-macro-crate",
- "proc-macro2",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "borsh-derive-internal"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "borsh-schema-derive-internal"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "bytecheck"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627"
-dependencies = [
- "bytecheck_derive",
- "ptr_meta",
- "simdutf8",
-]
-
-[[package]]
-name = "bytecheck_derive"
-version = "0.6.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
-name = "bytes"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
-
-[[package]]
-name = "cc"
-version = "1.0.83"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "chacha20"
-version = "0.9.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"
-dependencies = [
- "cfg-if",
- "cipher",
- "cpufeatures",
-]
-
-[[package]]
-name = "chacha20poly1305"
-version = "0.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35"
-dependencies = [
- "aead",
- "chacha20",
- "cipher",
- "poly1305",
- "zeroize",
-]
-
-[[package]]
-name = "cipher"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
-dependencies = [
- "crypto-common",
- "inout",
- "zeroize",
-]
-
-[[package]]
-name = "clap"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
-dependencies = [
- "clap_builder",
- "clap_derive",
-]
-
-[[package]]
-name = "clap_builder"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
-dependencies = [
- "anstream",
- "anstyle",
- "clap_lex",
- "strsim",
-]
-
-[[package]]
-name = "clap_derive"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "clap_lex"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
-
-[[package]]
-name = "colorchoice"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
-
-[[package]]
-name = "console"
-version = "0.15.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
-dependencies = [
- "encode_unicode",
- "lazy_static",
- "libc",
- "unicode-width",
- "windows-sys 0.45.0",
-]
-
-[[package]]
-name = "countme"
-version = "3.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
-
-[[package]]
-name = "cpufeatures"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "crc"
-version = "3.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe"
-dependencies = [
- "crc-catalog",
-]
-
-[[package]]
-name = "crc-catalog"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484"
-
-[[package]]
-name = "crunchy"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
-
-[[package]]
-name = "crypto-common"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
-dependencies = [
- "generic-array",
- "rand_core",
- "typenum",
-]
-
-[[package]]
-name = "crypto-mac"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
-dependencies = [
- "generic-array",
- "subtle",
-]
-
-[[package]]
-name = "crypto-mac"
-version = "0.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
-dependencies = [
- "generic-array",
- "subtle",
-]
-
-[[package]]
-name = "curve25519-dalek-ng"
-version = "4.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c359b7249347e46fb28804470d071c921156ad62b3eef5d34e2ba867533dec8"
-dependencies = [
- "byteorder",
- "digest",
- "rand_core",
- "subtle-ng",
- "zeroize",
-]
-
-[[package]]
-name = "dashmap"
-version = "5.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856"
-dependencies = [
- "cfg-if",
- "hashbrown 0.14.0",
- "lock_api",
- "once_cell",
- "parking_lot_core",
-]
-
-[[package]]
-name = "dialoguer"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87"
-dependencies = [
- "console",
- "shell-words",
- "tempfile",
- "zeroize",
-]
-
-[[package]]
-name = "digest"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "downcast-rs"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
-
-[[package]]
-name = "dyn-clone"
-version = "1.0.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555"
-
-[[package]]
-name = "ed25519"
-version = "1.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
-dependencies = [
- "signature",
-]
-
-[[package]]
-name = "ed25519-dalek"
-version = "1.0.1"
-source = "git+https://github.com/broxus/ed25519-dalek.git#e5d68fd1490a7f6a0d473c6c1b1acef868960471"
-dependencies = [
- "curve25519-dalek-ng",
- "ed25519",
- "rand",
- "serde",
- "sha2",
- "zeroize",
-]
-
-[[package]]
-name = "either"
-version = "1.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
-
-[[package]]
-name = "encode_unicode"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
-
-[[package]]
-name = "errno"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "136526188508e25c6fef639d7927dfb3e0e3084488bf202267829cf7fc23dbdd"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
-name = "everscale-ledger-wallet"
-version = "0.1.0"
-source = "git+https://github.com/broxus/everscale-ledger-wallet.git#3e8b56fd9238c46b7da62bc8c58cb62c7d80fa8d"
-dependencies = [
- "anyhow",
- "console",
- "dialoguer",
- "ed25519-dalek",
- "hex",
- "hidapi",
- "log",
- "num-derive",
- "num-traits",
- "parking_lot",
- "qstring",
- "semver",
- "thiserror",
- "uriparse",
-]
-
-[[package]]
-name = "fastrand"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "form_urlencoded"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "funty"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
-
-[[package]]
-name = "futures-core"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
-
-[[package]]
-name = "futures-macro"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "futures-task"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
-
-[[package]]
-name = "futures-util"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
-dependencies = [
- "futures-core",
- "futures-macro",
- "futures-task",
- "pin-project-lite",
- "pin-utils",
- "slab",
-]
-
-[[package]]
-name = "generic-array"
-version = "0.14.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
-dependencies = [
- "typenum",
- "version_check",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
-name = "gimli"
-version = "0.28.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
-dependencies = [
- "ahash 0.7.6",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
-dependencies = [
- "ahash 0.8.3",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
-
-[[package]]
-name = "heck"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
-
-[[package]]
-name = "hermit-abi"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
-
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
-[[package]]
-name = "hidapi"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "723777263b0dcc5730aec947496bd8c3940ba63c15f5633b288cc615f4f6af79"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "winapi",
-]
-
-[[package]]
-name = "hmac"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
-dependencies = [
- "crypto-mac 0.8.0",
- "digest",
-]
-
-[[package]]
-name = "hmac"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
-dependencies = [
- "crypto-mac 0.11.1",
- "digest",
-]
-
-[[package]]
-name = "hmac-drbg"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
-dependencies = [
- "digest",
- "generic-array",
- "hmac 0.8.1",
-]
-
-[[package]]
-name = "idna"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
-dependencies = [
- "unicode-bidi",
- "unicode-normalization",
-]
-
-[[package]]
-name = "inout"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
-dependencies = [
- "generic-array",
-]
-
-[[package]]
-name = "itoa"
-version = "1.0.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
-
-[[package]]
-name = "lazy_static"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
-
-[[package]]
-name = "ledger-app-everscale-tests"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "base64 0.21.4",
- "bigdecimal",
- "clap",
- "ed25519-dalek",
- "everscale-ledger-wallet",
- "hex",
- "nekoton",
- "nekoton-abi",
- "nekoton-contracts",
- "nekoton-utils",
- "rust_decimal",
- "tokio",
- "ton_block",
- "ton_types",
- "url",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.147"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
-
-[[package]]
-name = "libm"
-version = "0.2.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
-
-[[package]]
-name = "libsecp256k1"
-version = "0.7.0"
-source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2"
-dependencies = [
- "arrayref",
- "base64 0.13.1",
- "digest",
- "hmac-drbg",
- "libsecp256k1-core",
- "libsecp256k1-gen-ecmult",
- "libsecp256k1-gen-genmult",
- "rand",
- "serde",
- "sha2",
- "typenum",
-]
-
-[[package]]
-name = "libsecp256k1-core"
-version = "0.3.0"
-source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2"
-dependencies = [
- "crunchy",
- "digest",
- "subtle",
-]
-
-[[package]]
-name = "libsecp256k1-gen-ecmult"
-version = "0.3.0"
-source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2"
-dependencies = [
- "libsecp256k1-core",
-]
-
-[[package]]
-name = "libsecp256k1-gen-genmult"
-version = "0.3.0"
-source = "git+https://github.com/broxus/libsecp256k1.git#fae765aa1a0de4f0c7b7b386d0d46475943291b2"
-dependencies = [
- "libsecp256k1-core",
-]
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a9bad9f94746442c783ca431b22403b519cd7fbeed0533fdd6328b2f2212128"
-
-[[package]]
-name = "lock_api"
-version = "0.4.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
-name = "log"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
-
-[[package]]
-name = "lru"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909"
-dependencies = [
- "hashbrown 0.12.3",
-]
-
-[[package]]
-name = "memchr"
-version = "2.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c"
-
-[[package]]
-name = "memzero"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93c0d11ac30a033511ae414355d80f70d9f29a44a49140face477117a1ee90db"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
-dependencies = [
- "adler",
-]
-
-[[package]]
-name = "nekoton"
-version = "0.13.1"
-source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c"
-dependencies = [
- "anyhow",
- "async-trait",
- "base64 0.13.1",
- "chacha20poly1305",
- "curve25519-dalek-ng",
- "downcast-rs",
- "dyn-clone",
- "ed25519-dalek",
- "futures-util",
- "getrandom",
- "hex",
- "hmac 0.11.0",
- "log",
- "lru",
- "nekoton-abi",
- "nekoton-contracts",
- "nekoton-utils",
- "num-bigint",
- "once_cell",
- "parking_lot",
- "pbkdf2",
- "quick_cache",
- "rand",
- "secstr",
- "serde",
- "serde_json",
- "sha2",
- "thiserror",
- "tiny-bip39",
- "tiny-hderive",
- "tokio",
- "ton_abi",
- "ton_block",
- "ton_executor",
- "ton_types",
- "zeroize",
-]
-
-[[package]]
-name = "nekoton-abi"
-version = "0.13.0"
-source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "ed25519-dalek",
- "hex",
- "log",
- "nekoton-derive",
- "nekoton-utils",
- "num-bigint",
- "num-traits",
- "once_cell",
- "rustc-hash",
- "serde",
- "serde_json",
- "smallvec",
- "thiserror",
- "ton_abi",
- "ton_block",
- "ton_executor",
- "ton_types",
- "ton_vm",
-]
-
-[[package]]
-name = "nekoton-contracts"
-version = "0.13.0"
-source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c"
-dependencies = [
- "anyhow",
- "nekoton-abi",
- "once_cell",
- "thiserror",
- "ton_abi",
- "ton_block",
- "ton_types",
-]
-
-[[package]]
-name = "nekoton-derive"
-version = "0.13.0"
-source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c"
-dependencies = [
- "either",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "nekoton-utils"
-version = "0.13.0"
-source = "git+https://github.com/broxus/nekoton.git#d70dd09d4d482987541f1816fd3bce970710178c"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "chacha20poly1305",
- "ed25519-dalek",
- "hex",
- "hmac 0.11.0",
- "pbkdf2",
- "secstr",
- "serde",
- "sha2",
- "thiserror",
- "ton_block",
- "ton_types",
- "zeroize",
-]
-
-[[package]]
-name = "num"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af"
-dependencies = [
- "num-bigint",
- "num-complex",
- "num-integer",
- "num-iter",
- "num-rational",
- "num-traits",
-]
-
-[[package]]
-name = "num-bigint"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-complex"
-version = "0.4.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
-dependencies = [
- "num-traits",
-]
-
-[[package]]
-name = "num-derive"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "num-integer"
-version = "0.1.45"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
-dependencies = [
- "autocfg",
- "num-traits",
-]
-
-[[package]]
-name = "num-iter"
-version = "0.1.43"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
-dependencies = [
- "autocfg",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-rational"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
-dependencies = [
- "autocfg",
- "num-bigint",
- "num-integer",
- "num-traits",
-]
-
-[[package]]
-name = "num-traits"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "num_cpus"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
-dependencies = [
- "hermit-abi",
- "libc",
-]
-
-[[package]]
-name = "object"
-version = "0.32.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.18.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
-dependencies = [
- "parking_lot_core",
-]
-
-[[package]]
-name = "opaque-debug"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
-
-[[package]]
-name = "parking_lot"
-version = "0.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "password-hash"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8"
-dependencies = [
- "base64ct",
- "rand_core",
- "subtle",
-]
-
-[[package]]
-name = "pbkdf2"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f05894bce6a1ba4be299d0c5f29563e08af2bc18bb7d48313113bed71e904739"
-dependencies = [
- "crypto-mac 0.11.1",
- "hmac 0.11.0",
- "password-hash",
- "sha2",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
-
-[[package]]
-name = "pin-utils"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
-
-[[package]]
-name = "poly1305"
-version = "0.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf"
-dependencies = [
- "cpufeatures",
- "opaque-debug",
- "universal-hash",
-]
-
-[[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
-name = "proc-macro-crate"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
-dependencies = [
- "toml",
-]
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.66"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "ptr_meta"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
-dependencies = [
- "ptr_meta_derive",
-]
-
-[[package]]
-name = "ptr_meta_derive"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "qstring"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "quick_cache"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5253a3a0d56548d5b0be25414171dc780cc6870727746d05bd2bde352eee96c5"
-dependencies = [
- "ahash 0.8.3",
- "hashbrown 0.13.2",
- "parking_lot",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "radium"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
-
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags 1.3.2",
-]
-
-[[package]]
-name = "rend"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab"
-dependencies = [
- "bytecheck",
-]
-
-[[package]]
-name = "rkyv"
-version = "0.7.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58"
-dependencies = [
- "bitvec",
- "bytecheck",
- "hashbrown 0.12.3",
- "ptr_meta",
- "rend",
- "rkyv_derive",
- "seahash",
- "tinyvec",
- "uuid",
-]
-
-[[package]]
-name = "rkyv_derive"
-version = "0.7.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
-name = "rust_decimal"
-version = "1.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd"
-dependencies = [
- "arrayvec",
- "borsh",
- "bytes",
- "num-traits",
- "rand",
- "rkyv",
- "serde",
- "serde_json",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
-
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
-[[package]]
-name = "rustix"
-version = "0.38.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662"
-dependencies = [
- "bitflags 2.4.0",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "ryu"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
-
-[[package]]
-name = "scopeguard"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-
-[[package]]
-name = "seahash"
-version = "4.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
-
-[[package]]
-name = "secstr"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e04f657244f605c4cf38f6de5993e8bd050c8a303f86aeabff142d5c7c113e12"
-dependencies = [
- "libc",
- "serde",
-]
-
-[[package]]
-name = "semver"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
-
-[[package]]
-name = "serde"
-version = "1.0.188"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.188"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.106"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cc66a619ed80bf7a0f6b17dd063a84b88f6dea1813737cf469aef1d081142c2"
-dependencies = [
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "sha2"
-version = "0.9.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
-dependencies = [
- "block-buffer",
- "cfg-if",
- "cpufeatures",
- "digest",
- "opaque-debug",
-]
-
-[[package]]
-name = "shell-words"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
-
-[[package]]
-name = "signature"
-version = "1.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
-
-[[package]]
-name = "simdutf8"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
-
-[[package]]
-name = "slab"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
-
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "subtle"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
-
-[[package]]
-name = "subtle-ng"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "734676eb262c623cec13c3155096e08d1f8f29adce39ba17948b18dad1e54142"
-
-[[package]]
-name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
-version = "2.0.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "239814284fd6f1a4ffe4ca893952cdd93c224b6a1571c9a9eadd670295c0c9e2"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "tap"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
-
-[[package]]
-name = "tempfile"
-version = "3.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
-dependencies = [
- "cfg-if",
- "fastrand",
- "redox_syscall",
- "rustix",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "thiserror"
-version = "1.0.48"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7"
-dependencies = [
- "thiserror-impl",
-]
-
-[[package]]
-name = "thiserror-impl"
-version = "1.0.48"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "tiny-bip39"
-version = "0.8.0"
-source = "git+https://github.com/broxus/tiny-bip39.git#d2a73124c2fbead4f969f8a5e075ee22040f63cc"
-dependencies = [
- "anyhow",
- "hmac 0.11.0",
- "once_cell",
- "pbkdf2",
- "rand",
- "rustc-hash",
- "sha2",
- "thiserror",
- "unicode-normalization",
- "zeroize",
-]
-
-[[package]]
-name = "tiny-hderive"
-version = "0.3.0"
-source = "git+https://github.com/broxus/tiny-hderive.git#050986d85711497076ba552ce53806885274a4d2"
-dependencies = [
- "base58",
- "hmac 0.11.0",
- "libsecp256k1",
- "memzero",
- "sha2",
-]
-
-[[package]]
-name = "tinyvec"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
-dependencies = [
- "tinyvec_macros",
-]
-
-[[package]]
-name = "tinyvec_macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
-
-[[package]]
-name = "tokio"
-version = "1.32.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
-dependencies = [
- "backtrace",
- "num_cpus",
- "pin-project-lite",
- "tokio-macros",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
-
-[[package]]
-name = "toml"
-version = "0.5.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "ton_abi"
-version = "2.1.0"
-source = "git+https://github.com/broxus/ton-labs-abi#b8834529ef8fa121d534fca6554c0e95d4019998"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "byteorder",
- "ed25519",
- "ed25519-dalek",
- "hex",
- "num-bigint",
- "num-traits",
- "serde",
- "serde_json",
- "sha2",
- "smallvec",
- "thiserror",
- "ton_block",
- "ton_types",
-]
-
-[[package]]
-name = "ton_block"
-version = "1.9.73"
-source = "git+https://github.com/broxus/ton-labs-block#66b3ccb8e6187e6d9f611f6541c0f59d3eb77cbf"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "crc",
- "ed25519",
- "ed25519-dalek",
- "hex",
- "log",
- "num",
- "num-traits",
- "rand",
- "rustc-hash",
- "sha2",
- "smallvec",
- "thiserror",
- "ton_types",
-]
-
-[[package]]
-name = "ton_executor"
-version = "1.15.54"
-source = "git+https://github.com/broxus/ton-labs-executor#2a38890d53f9c3dad84b3fb9a58e3bb62ba20f44"
-dependencies = [
- "anyhow",
- "log",
- "thiserror",
- "ton_block",
- "ton_types",
- "ton_vm",
-]
-
-[[package]]
-name = "ton_types"
-version = "1.10.2"
-source = "git+https://github.com/broxus/ton-labs-types#3324562d7ff1ebec66d996128573966c1b53862b"
-dependencies = [
- "anyhow",
- "base64 0.13.1",
- "countme",
- "crc",
- "dashmap",
- "hex",
- "log",
- "num",
- "num-derive",
- "num-traits",
- "rand",
- "rustc-hash",
- "sha2",
- "smallvec",
- "thiserror",
-]
-
-[[package]]
-name = "ton_vm"
-version = "1.8.29"
-source = "git+https://github.com/broxus/ton-labs-vm.git#497865fb3aabf02afea610f9c16f265b492c23a6"
-dependencies = [
- "anyhow",
- "ed25519",
- "ed25519-dalek",
- "hex",
- "lazy_static",
- "log",
- "num",
- "num-traits",
- "rand",
- "sha2",
- "smallvec",
- "thiserror",
- "ton_block",
- "ton_types",
-]
-
-[[package]]
-name = "typenum"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
-
-[[package]]
-name = "unicode-bidi"
-version = "0.3.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
-
-[[package]]
-name = "unicode-normalization"
-version = "0.1.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
-dependencies = [
- "tinyvec",
-]
-
-[[package]]
-name = "unicode-width"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
-
-[[package]]
-name = "universal-hash"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
-dependencies = [
- "crypto-common",
- "subtle",
-]
-
-[[package]]
-name = "uriparse"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
-dependencies = [
- "fnv",
- "lazy_static",
-]
-
-[[package]]
-name = "url"
-version = "2.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
-]
-
-[[package]]
-name = "utf8parse"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
-
-[[package]]
-name = "uuid"
-version = "1.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d"
-
-[[package]]
-name = "version_check"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "wyz"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
-dependencies = [
- "tap",
-]
-
-[[package]]
-name = "zeroize"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
-dependencies = [
- "zeroize_derive",
-]
-
-[[package]]
-name = "zeroize_derive"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.32",
-]
diff --git a/tests/Cargo.toml b/tests/Cargo.toml
deleted file mode 100644
index fe7989b..0000000
--- a/tests/Cargo.toml
+++ /dev/null
@@ -1,30 +0,0 @@
-[package]
-name = "ledger-app-everscale-tests"
-version = "0.1.0"
-edition = "2021"
-description = "Ledger-app integration tests using Everscale tools"
-authors = ["Broxus team"]
-
-[dependencies]
-anyhow = "1.0"
-base64 = "0.21.3"
-bigdecimal = "0.4.1"
-clap = { version = "4.0.18", features = ["derive"] }
-hex = "0.4.3"
-rust_decimal = "1"
-tokio = { version = "1.21.2", features = ["sync", "rt-multi-thread", "macros"] }
-url = { version = "2.3.1" }
-
-# Basic types
-ed25519-dalek = { git = "https://github.com/broxus/ed25519-dalek.git" }
-ton_block = { git = "https://github.com/broxus/ton-labs-block" }
-ton_types = { git = "https://github.com/broxus/ton-labs-types" }
-
-# Ledger wallet
-everscale-ledger-wallet = { git = "https://github.com/broxus/everscale-ledger-wallet.git" }
-
-# Nekoton SDK
-nekoton = { git = "https://github.com/broxus/nekoton.git", default-features = false }
-nekoton-abi = { git = "https://github.com/broxus/nekoton.git" }
-nekoton-utils = { git = "https://github.com/broxus/nekoton.git" }
-nekoton-contracts = { git = "https://github.com/broxus/nekoton.git" }
diff --git a/tests/python/apps/__init__.py b/tests/application_client/__init__.py
similarity index 100%
rename from tests/python/apps/__init__.py
rename to tests/application_client/__init__.py
diff --git a/tests/application_client/everscale_command_sender.py b/tests/application_client/everscale_command_sender.py
new file mode 100644
index 0000000..b774bb6
--- /dev/null
+++ b/tests/application_client/everscale_command_sender.py
@@ -0,0 +1,176 @@
+from enum import IntEnum
+from typing import Generator, List, Optional
+from contextlib import contextmanager
+
+from ragger.backend.interface import BackendInterface, RAPDU
+
+MAX_APDU_LEN: int = 255
+
+CLA: int = 0xE0
+
+
+class P1(IntEnum):
+ # Parameter 1 for first APDU number.
+ P1_START = 0x00
+ # Parameter 1 for maximum APDU number.
+ P1_MAX = 0x03
+ # Parameter 1 for screen confirmation for GET_PUBLIC_KEY.
+ P1_CONFIRM = 0x01
+
+
+class P2(IntEnum):
+ # Parameter 2 for last APDU to receive.
+ P2_LAST = 0x00
+ # Parameter 2 for more APDU to receive.
+ P2_MORE = 0x80
+
+
+class InsType(IntEnum):
+ GET_APP_CONFIGURATION = 0x01
+ GET_PUBLIC_KEY = 0x02
+ SIGN_MESSAGE = 0x03
+ GET_ADDRESS = 0x04
+ SIGN_TRANSACTION = 0x05
+
+
+class WalletType(IntEnum):
+ WALLET_V3 = 0
+ EVER_WALLET = 1
+ SAFE_MULTISIG_WALLET = 2
+ SAFE_MULTISIG_WALLET_24H = 3
+ SETCODE_MULTISIG_WALLET = 4
+ BRIDGE_MULTISIG_WALLET = 5
+ SURF_WALLET = 6
+ MULTISIG_2 = 7
+ MULTISIG_2_1 = 8
+
+
+class Errors(IntEnum):
+ SW_INVALID_DATA = 0x6B00
+ SW_CELL_UNDERFLOW = 0x6B01
+ SW_RANGE_CHECK_FAIL = 0x6B02
+ SW_WRONG_LABEL = 0x6B03
+ SW_INVALID_FLAG = 0x6B04
+ SW_END_OF_STREAM = 0x6B05
+ SW_SLICE_IS_EMPTY = 0x6B06
+ SW_INVALID_KEY = 0x6B07
+ SW_CELL_IS_EMPTY = 0x6B08
+ SW_INVALID_HASH = 0x6B09
+ SW_INVALID_CELL_INDEX = 0x6B10
+ SW_INVALID_REQUEST = 0x6B11
+ SW_INVALID_FUNCTION_ID = 0x6B12
+ SW_INVALID_SRC_ADDRESS = 0x6B13
+ SW_INVALID_WALLET_ID = 0x6B14
+ SW_INVALID_WALLET_TYPE = 0x6B15
+ SW_INVALID_TICKER_LENGTH = 0x6B16
+ SW_DENY = 0x6985
+ # Status Word from everscale app
+ # SW_WRONG_P1P2 = 0x6A86
+ # SW_WRONG_DATA_LENGTH = 0x6A87
+ # SW_INS_NOT_SUPPORTED = 0x6D00
+ # SW_CLA_NOT_SUPPORTED = 0x6E00
+ # SW_WRONG_RESPONSE_LENGTH = 0xB000
+ # SW_DISPLAY_BIP32_PATH_FAIL = 0xB001
+ # SW_DISPLAY_ADDRESS_FAIL = 0xB002
+ # SW_DISPLAY_AMOUNT_FAIL = 0xB003
+ # SW_WRONG_TX_LENGTH = 0xB004
+ # SW_TX_PARSING_FAIL = 0xB005
+ # SW_TX_HASH_FAIL = 0xB006
+ # SW_BAD_STATE = 0xB007
+ # SW_SIGNATURE_FAIL = 0xB008
+
+
+def split_message(message: bytes, max_size: int) -> List[bytes]:
+ return [message[x : x + max_size] for x in range(0, len(message), max_size)]
+
+
+class EverscaleCommandSender:
+ def __init__(self, backend: BackendInterface) -> None:
+ self.backend = backend
+
+ def get_app_and_version(self) -> RAPDU:
+ return self.backend.exchange(
+ cla=0xB0, # specific CLA for BOLOS
+ ins=0x01, # specific INS for get_app_and_version
+ p1=P1.P1_START,
+ p2=P2.P2_LAST,
+ data=b"",
+ )
+
+ def get_app_config(self) -> RAPDU:
+ return self.backend.exchange(
+ cla=CLA,
+ ins=InsType.GET_APP_CONFIGURATION,
+ p1=P1.P1_START,
+ p2=P2.P2_LAST,
+ data=b"",
+ )
+
+ def get_public_key(self, account_number: int) -> RAPDU:
+ return self.backend.exchange(
+ cla=CLA,
+ ins=InsType.GET_PUBLIC_KEY,
+ p1=P1.P1_START,
+ p2=P2.P2_LAST,
+ data=account_number.to_bytes(4, "big"),
+ )
+
+ @contextmanager
+ def get_public_key_with_confirmation(
+ self, account_number: int
+ ) -> Generator[None, None, None]:
+ with self.backend.exchange_async(
+ cla=CLA,
+ ins=InsType.GET_PUBLIC_KEY,
+ p1=P1.P1_CONFIRM,
+ p2=P2.P2_LAST,
+ data=account_number.to_bytes(4, "big"),
+ ) as response:
+ yield response
+
+ def get_address(self, account_number: int, wallet_type: WalletType) -> RAPDU:
+ return self.backend.exchange(
+ cla=CLA,
+ ins=InsType.GET_ADDRESS,
+ p1=P1.P1_START,
+ p2=P2.P2_LAST,
+ data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big"),
+ )
+
+ @contextmanager
+ def get_address_with_confirmation(
+ self, account_number: int, wallet_type: WalletType
+ ) -> Generator[None, None, None]:
+ with self.backend.exchange_async(
+ cla=CLA,
+ ins=InsType.GET_ADDRESS,
+ p1=P1.P1_CONFIRM,
+ p2=P2.P2_LAST,
+ data=account_number.to_bytes(4, "big") + wallet_type.to_bytes(1, "big"),
+ ) as response:
+ yield response
+
+ @contextmanager
+ def sign_message(self, payload: bytes) -> Generator[None, None, None]:
+ with self.backend.exchange_async(
+ cla=CLA,
+ ins=InsType.SIGN_MESSAGE,
+ p1=P1.P1_CONFIRM,
+ p2=P2.P2_LAST,
+ data=payload,
+ ) as response:
+ yield response
+
+ @contextmanager
+ def sign_tx(self, transaction: bytes) -> Generator[None, None, None]:
+ with self.backend.exchange_async(
+ cla=CLA,
+ ins=InsType.SIGN_TRANSACTION,
+ p1=P1.P1_CONFIRM,
+ p2=P2.P2_LAST,
+ data=transaction,
+ ) as response:
+ yield response
+
+ def get_async_response(self) -> Optional[RAPDU]:
+ return self.backend.last_async_response
diff --git a/tests/application_client/everscale_response_unpacker.py b/tests/application_client/everscale_response_unpacker.py
new file mode 100644
index 0000000..9c6fed4
--- /dev/null
+++ b/tests/application_client/everscale_response_unpacker.py
@@ -0,0 +1,77 @@
+from typing import Tuple
+from struct import unpack
+
+# remainder, data_len, data
+def pop_sized_buf_from_buffer(buffer:bytes, size:int) -> Tuple[bytes, bytes]:
+ return buffer[size:], buffer[0:size]
+
+# remainder, data_len, data
+def pop_size_prefixed_buf_from_buf(buffer:bytes) -> Tuple[bytes, int, bytes]:
+ data_len = buffer[0]
+ return buffer[1+data_len:], data_len, buffer[1:data_len+1]
+
+# Unpack from response:
+# response = app_name (var)
+def unpack_get_app_name_response(response: bytes) -> str:
+ return response.decode("ascii")
+
+# Unpack from response:
+# response = MAJOR (1)
+# MINOR (1)
+# PATCH (1)
+def unpack_get_version_response(response: bytes) -> Tuple[int, int, int]:
+ assert len(response) == 3
+ major, minor, patch = unpack("BBB", response)
+ return (major, minor, patch)
+
+# Unpack from response:
+# response = format_id (1)
+# app_name_raw_len (1)
+# app_name_raw (var)
+# version_raw_len (1)
+# version_raw (var)
+# unused_len (1)
+# unused (var)
+def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]:
+ response, _ = pop_sized_buf_from_buffer(response, 1)
+ response, _, app_name_raw = pop_size_prefixed_buf_from_buf(response)
+ response, _, version_raw = pop_size_prefixed_buf_from_buf(response)
+ response, _, _ = pop_size_prefixed_buf_from_buf(response)
+
+ assert len(response) == 0
+
+ return app_name_raw.decode("ascii"), version_raw.decode("ascii")
+
+# Unpack from response:
+# response = pub_key_len (1)
+# pub_key (var)
+def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes]:
+ response, pub_key_len, pub_key = pop_size_prefixed_buf_from_buf(response)
+
+ assert pub_key_len == 32
+ assert len(response) == 0
+
+ return pub_key_len, pub_key
+
+# Unpack from response:
+# response = address_len (1)
+# address (var)
+def unpack_get_address_response(response: bytes) -> Tuple[int, bytes]:
+ response, address_len, address = pop_size_prefixed_buf_from_buf(response)
+
+ assert address_len == 32
+ assert len(response) == 0
+
+ return address_len, address
+
+# Unpack from response:
+# response = der_sig_len (1)
+# der_sig (var)
+# v (1)
+def unpack_sign_tx_response(response: bytes) -> Tuple[int, bytes, int]:
+ response, der_sig_len, der_sig = pop_size_prefixed_buf_from_buf(response)
+ response, v = pop_sized_buf_from_buffer(response, 1)
+
+ assert len(response) == 0
+
+ return der_sig_len, der_sig, int.from_bytes(v, byteorder='big')
diff --git a/tests/application_client/everscale_transaction.py b/tests/application_client/everscale_transaction.py
new file mode 100644
index 0000000..31aa1d7
--- /dev/null
+++ b/tests/application_client/everscale_transaction.py
@@ -0,0 +1,188 @@
+# from application_client.everscale_command_sender import WalletType
+
+# class Transaction:
+# ADDRESS_LENGTH = 32
+# CHAIN_ID_LENGTH = 4
+
+# FLAG_WITH_WALLET_ID = 0x01
+# FLAG_WITH_WORKCHAIN_ID = 0x02
+# FLAG_WITH_ADDRESS = 0x04
+# FLAG_WITH_CHAIN_ID = 0x08
+
+# def __init__(self,
+# decimals: int,
+# ticker: str,
+# message: bytes,
+# current_wallet_type: WalletType,
+# workchain_id: int | None = None,
+# prepend_address: bytes | None = None,
+# chain_id: bytes | None = None) -> None:
+# """
+# Construct a Transaction.
+
+# The metadata byte is deduced as follows:
+# - FLAG_WITH_WALLET_ID is set if a current_wallet_type is provided and
+# it differs from the origin_wallet_type.
+# - FLAG_WITH_WORKCHAIN_ID is set if workchain_id is provided.
+# - FLAG_WITH_ADDRESS is set if prepend_address is provided.
+# - FLAG_WITH_CHAIN_ID is set if chain_id is provided.
+
+# If current_wallet_type is None or equals origin_wallet_type, then that field is omitted
+# and on deserialization the origin_wallet_type will be used.
+# """
+# self.decimals = decimals
+# self.ticker = ticker
+# self.message = message
+# self.workchain_id = workchain_id
+# self.prepend_address = prepend_address
+# self.chain_id = chain_id
+
+# # Deduce metadata flags based on optional inputs.
+# metadata = 0
+# if current_wallet_type is not None:
+# metadata |= self.FLAG_WITH_WALLET_ID
+# self.current_wallet_type = current_wallet_type
+# else:
+# # Do not include the field; on the device, it will be set to origin_wallet_type.
+# self.current_wallet_type = None
+
+# if workchain_id is not None:
+# metadata |= self.FLAG_WITH_WORKCHAIN_ID
+
+# if prepend_address is not None:
+# if len(prepend_address) != self.ADDRESS_LENGTH:
+# raise ValueError(f"prepend_address must be {self.ADDRESS_LENGTH} bytes")
+# metadata |= self.FLAG_WITH_ADDRESS
+
+# if chain_id is not None:
+# if len(chain_id) != self.CHAIN_ID_LENGTH:
+# raise ValueError(f"chain_id must be {self.CHAIN_ID_LENGTH} bytes")
+# metadata |= self.FLAG_WITH_CHAIN_ID
+
+# self.metadata = metadata
+
+# # Nice-to-haves: check ticker length constraints.
+# ticker_len = len(ticker)
+# if ticker_len == 0 or ticker_len > 10:
+# raise ValueError("Ticker length must be between 1 and 10 bytes.")
+
+# def serialize(self) -> bytes:
+# """
+# Serialize the transaction into a byte-buffer with the following structure:
+
+# [decimals:1] [ticker_length:1] [ticker:N] [metadata:1]
+# [optional fields (if flagged)...] [message:remaining bytes]
+# """
+# result = bytearray()
+# # 1. Decimals (1 byte)
+# result.append(self.decimals)
+
+# # 2. Ticker: length (1 byte) followed by its ASCII bytes
+# ticker_bytes = self.ticker.encode("ascii")
+# ticker_len = len(ticker_bytes)
+# result.append(ticker_len)
+# result.extend(ticker_bytes)
+
+# # 3. Metadata (1 byte; deduced from optional parameters)
+# result.append(self.metadata)
+
+# # 4. Conditionally append optional fields based on metadata flags.
+# if self.metadata & self.FLAG_WITH_WALLET_ID:
+# # current_wallet_type is provided and differs from origin_wallet_type.
+# result.append(self.current_wallet_type)
+# # Workchain id.
+# if self.metadata & self.FLAG_WITH_WORKCHAIN_ID:
+# result.append(self.workchain_id)
+# # Prepend address.
+# if self.metadata & self.FLAG_WITH_ADDRESS:
+# result.extend(self.prepend_address)
+# # Chain id.
+# if self.metadata & self.FLAG_WITH_CHAIN_ID:
+# result.extend(self.chain_id)
+
+# # 5. Append the message (payload).
+# result.extend(self.message)
+
+# return bytes(result)
+
+# @classmethod
+# def from_bytes(cls, data: bytes) -> "Transaction":
+# """
+# Deserialize a byte-buffer into a Transaction object.
+
+# The parsing order in the buffer is:
+# decimals (1 byte) ->
+# ticker_length (1 byte) ->
+# ticker ->
+# metadata (1 byte) ->
+# [optional fields... based on metadata] ->
+# message (remaining bytes)
+
+# If the metadata does NOT include FLAG_WITH_WALLET_ID, then current_wallet_type
+# defaults to origin_wallet_type.
+# """
+# offset = 0
+
+# # Read decimals (1 byte)
+# if len(data) < offset + 1:
+# raise ValueError("Data too short for decimals")
+# decimals = data[offset]
+# offset += 1
+
+# # Read ticker: first its length (1 byte) then the ticker string
+# if len(data) < offset + 1:
+# raise ValueError("Data too short for ticker length")
+# ticker_len = data[offset]
+# offset += 1
+# if len(data) < offset + ticker_len:
+# raise ValueError("Data too short for ticker")
+# ticker = data[offset:offset+ticker_len].decode("ascii")
+# offset += ticker_len
+
+# # Read metadata (1 byte)
+# if len(data) < offset + 1:
+# raise ValueError("Data too short for metadata")
+# metadata = data[offset]
+# offset += 1
+
+# # Read optional fields based on metadata flags.
+# current_wallet_type = None
+# if metadata & cls.FLAG_WITH_WALLET_ID:
+# if len(data) < offset + 1:
+# raise ValueError("Data too short for current_wallet_type")
+# current_wallet_type = data[offset]
+# offset += 1
+
+# workchain_id = None
+# if metadata & cls.FLAG_WITH_WORKCHAIN_ID:
+# if len(data) < offset + 1:
+# raise ValueError("Data too short for workchain_id")
+# workchain_id = data[offset]
+# offset += 1
+
+# prepend_address = None
+# if metadata & cls.FLAG_WITH_ADDRESS:
+# if len(data) < offset + cls.ADDRESS_LENGTH:
+# raise ValueError("Data too short for prepend_address")
+# prepend_address = data[offset:offset+cls.ADDRESS_LENGTH]
+# offset += cls.ADDRESS_LENGTH
+
+# chain_id = None
+# if metadata & cls.FLAG_WITH_CHAIN_ID:
+# if len(data) < offset + cls.CHAIN_ID_LENGTH:
+# raise ValueError("Data too short for chain_id")
+# chain_id = data[offset:offset+cls.CHAIN_ID_LENGTH]
+# offset += cls.CHAIN_ID_LENGTH
+
+# # The remaining bytes are the message.
+# message = data[offset:]
+
+# return cls(
+# decimals=decimals,
+# ticker=ticker,
+# message=message,
+# current_wallet_type=current_wallet_type,
+# workchain_id=workchain_id,
+# prepend_address=prepend_address,
+# chain_id=chain_id
+# )
diff --git a/tests/application_client/everscale_utils.py b/tests/application_client/everscale_utils.py
new file mode 100644
index 0000000..fd96e62
--- /dev/null
+++ b/tests/application_client/everscale_utils.py
@@ -0,0 +1,61 @@
+from io import BytesIO
+from typing import Optional, Literal
+
+
+UINT64_MAX: int = 2**64-1
+UINT32_MAX: int = 2**32-1
+UINT16_MAX: int = 2**16-1
+
+
+def write_varint(n: int) -> bytes:
+ if n < 0xFC:
+ return n.to_bytes(1, byteorder="little")
+
+ if n <= UINT16_MAX:
+ return b"\xFD" + n.to_bytes(2, byteorder="little")
+
+ if n <= UINT32_MAX:
+ return b"\xFE" + n.to_bytes(4, byteorder="little")
+
+ if n <= UINT64_MAX:
+ return b"\xFF" + n.to_bytes(8, byteorder="little")
+
+ raise ValueError(f"Can't write to varint: '{n}'!")
+
+
+def read_varint(buf: BytesIO,
+ prefix: Optional[bytes] = None) -> int:
+ b: bytes = prefix if prefix else buf.read(1)
+
+ if not b:
+ raise ValueError(f"Can't read prefix: '{b.hex()}'!")
+
+ n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1
+
+ b = buf.read(n) if n > 1 else b
+
+ if len(b) != n:
+ raise ValueError("Can't read varint!")
+
+ return int.from_bytes(b, byteorder="little")
+
+
+def read(buf: BytesIO, size: int) -> bytes:
+ b: bytes = buf.read(size)
+
+ if len(b) < size:
+ raise ValueError(f"Can't read {size} bytes in buffer!")
+
+ return b
+
+
+def read_uint(buf: BytesIO,
+ bit_len: int,
+ byteorder: Literal['big', 'little'] = 'little') -> int:
+ size: int = bit_len // 8
+ b: bytes = buf.read(size)
+
+ if len(b) < size:
+ raise ValueError(f"Can't read u{bit_len} in buffer!")
+
+ return int.from_bytes(b, byteorder)
diff --git a/tests/speculos/ledger_client/__init__.py b/tests/application_client/py.typed
similarity index 100%
rename from tests/speculos/ledger_client/__init__.py
rename to tests/application_client/py.typed
diff --git a/tests/conftest.py b/tests/conftest.py
new file mode 100644
index 0000000..76b5e0c
--- /dev/null
+++ b/tests/conftest.py
@@ -0,0 +1,24 @@
+from ragger.conftest import configuration
+
+###########################
+### CONFIGURATION START ###
+###########################
+
+# You can configure optional parameters by overriding the value of ragger.configuration.OPTIONAL_CONFIGURATION
+# Please refer to ragger/conftest/configuration.py for their descriptions and accepted values
+
+# Define pytest markers
+def pytest_configure(config):
+ config.addinivalue_line(
+ "markers",
+ "active_test_scope: marks tests related to application name functionality",
+ )
+ # Add more markers here as needed
+
+
+#########################
+### CONFIGURATION END ###
+#########################
+
+# Pull all features from the base ragger conftest using the overridden configuration
+pytest_plugins = ("ragger.conftest.base_conftest", )
diff --git a/tests/requirements.txt b/tests/requirements.txt
new file mode 100644
index 0000000..dd07dfb
--- /dev/null
+++ b/tests/requirements.txt
@@ -0,0 +1,4 @@
+pytest
+ragger[speculos,ledgerwallet]>=1.11.4
+ecdsa>=0.16.1,<0.17.0
+pycryptodome
diff --git a/tests/speculos/setup.cfg b/tests/setup.cfg
similarity index 66%
rename from tests/speculos/setup.cfg
rename to tests/setup.cfg
index c79fd88..2d024b3 100644
--- a/tests/speculos/setup.cfg
+++ b/tests/setup.cfg
@@ -1,5 +1,5 @@
[tool:pytest]
-addopts = --strict-markers
+addopts = --strict-markers -m active_test_scope
[pylint]
disable = C0114, # missing-module-docstring
@@ -7,11 +7,14 @@ disable = C0114, # missing-module-docstring
C0116, # missing-function-docstring
C0103, # invalid-name
R0801, # duplicate-code
- R0913 # too-many-arguments
+ R0913, # too-many-arguments
+ R0917 # too-many-positional-arguments
+
+max-line-length=120
extension-pkg-whitelist=hid
[pycodestyle]
-max-line-length = 90
+max-line-length = 100
[mypy-hid.*]
ignore_missing_imports = True
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png
new file mode 100644
index 0000000..271e837
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png
new file mode 100644
index 0000000..6b9235b
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png
new file mode 100644
index 0000000..4321e60
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png
new file mode 100644
index 0000000..271e837
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00000.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png
new file mode 100644
index 0000000..6b9235b
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00001.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png
new file mode 100644
index 0000000..45c08d4
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00002.png differ
diff --git a/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_get_address_wallet_v3_confirm_refused/00003.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png
new file mode 100644
index 0000000..1a0afc1
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png
new file mode 100644
index 0000000..7200206
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png
new file mode 100644
index 0000000..7bc85c6
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png
new file mode 100644
index 0000000..4321e60
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png
new file mode 100644
index 0000000..1a0afc1
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00000.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png
new file mode 100644
index 0000000..f8feb4c
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00001.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png
new file mode 100644
index 0000000..45c08d4
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00002.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png
new file mode 100644
index 0000000..f8feb4c
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00003.png differ
diff --git a/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png
new file mode 100644
index 0000000..45c08d4
Binary files /dev/null and b/tests/snapshots/flex/test_get_public_key_confirm_refused/00004.png differ
diff --git a/tests/snapshots/flex/test_sign_message/00000.png b/tests/snapshots/flex/test_sign_message/00000.png
new file mode 100644
index 0000000..65ad8cb
Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00000.png differ
diff --git a/tests/snapshots/flex/test_sign_message/00001.png b/tests/snapshots/flex/test_sign_message/00001.png
new file mode 100644
index 0000000..4842bfe
Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00001.png differ
diff --git a/tests/snapshots/flex/test_sign_message/00002.png b/tests/snapshots/flex/test_sign_message/00002.png
new file mode 100644
index 0000000..b48c0c2
Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00002.png differ
diff --git a/tests/snapshots/flex/test_sign_message/00003.png b/tests/snapshots/flex/test_sign_message/00003.png
new file mode 100644
index 0000000..8b981d4
Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00003.png differ
diff --git a/tests/snapshots/flex/test_sign_message/00004.png b/tests/snapshots/flex/test_sign_message/00004.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_sign_message/00004.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png
new file mode 100644
index 0000000..ee3f74f
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00000.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png
new file mode 100644
index 0000000..a080152
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00001.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png
new file mode 100644
index 0000000..f0c2eda
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00002.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png
new file mode 100644
index 0000000..be51a9d
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00003.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_burn_usdt/00004.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00000.png b/tests/snapshots/flex/test_sign_tx_confirm/00000.png
new file mode 100644
index 0000000..ee3f74f
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00000.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00001.png b/tests/snapshots/flex/test_sign_tx_confirm/00001.png
new file mode 100644
index 0000000..e4c5c68
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00001.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00002.png b/tests/snapshots/flex/test_sign_tx_confirm/00002.png
new file mode 100644
index 0000000..f0c2eda
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00002.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00003.png b/tests/snapshots/flex/test_sign_tx_confirm/00003.png
new file mode 100644
index 0000000..be51a9d
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00003.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_confirm/00004.png b/tests/snapshots/flex/test_sign_tx_confirm/00004.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_confirm/00004.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00000.png b/tests/snapshots/flex/test_sign_tx_transfer/00000.png
new file mode 100644
index 0000000..ee3f74f
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00000.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00001.png b/tests/snapshots/flex/test_sign_tx_transfer/00001.png
new file mode 100644
index 0000000..f489d2e
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00001.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00002.png b/tests/snapshots/flex/test_sign_tx_transfer/00002.png
new file mode 100644
index 0000000..f0c2eda
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00002.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00003.png b/tests/snapshots/flex/test_sign_tx_transfer/00003.png
new file mode 100644
index 0000000..be51a9d
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00003.png differ
diff --git a/tests/snapshots/flex/test_sign_tx_transfer/00004.png b/tests/snapshots/flex/test_sign_tx_transfer/00004.png
new file mode 100644
index 0000000..ed74cf1
Binary files /dev/null and b/tests/snapshots/flex/test_sign_tx_transfer/00004.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png
new file mode 100644
index 0000000..a487005
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png
new file mode 100644
index 0000000..b0fb95c
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png
new file mode 100644
index 0000000..79ec8e7
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00003.png differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png
similarity index 100%
rename from tests/speculos/screenshots/get_pubkey/approve/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00004.png
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00005.png
similarity index 100%
rename from tests/speculos/screenshots/get_pubkey/reject/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_accepted/00005.png
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png
new file mode 100644
index 0000000..a487005
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00000.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png
new file mode 100644
index 0000000..b0fb95c
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00001.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png
new file mode 100644
index 0000000..79ec8e7
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00002.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00003.png differ
diff --git a/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png
new file mode 100644
index 0000000..c4c84cf
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00004.png differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00000.png b/tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00005.png
similarity index 100%
rename from tests/speculos/screenshots/sign/sign_message/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_address_wallet_v3_confirm_refused/00005.png
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png
new file mode 100644
index 0000000..653262d
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png
new file mode 100644
index 0000000..94681e7
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png
new file mode 100644
index 0000000..9048fa4
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00003.png differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00004.png
similarity index 100%
rename from tests/speculos/screenshots/sign/sign_reject/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00004.png
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_public_key_confirm_accepted/00005.png
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png
new file mode 100644
index 0000000..653262d
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00000.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png
new file mode 100644
index 0000000..94681e7
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00001.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png
new file mode 100644
index 0000000..9048fa4
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00002.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00003.png differ
diff --git a/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png
new file mode 100644
index 0000000..c4c84cf
Binary files /dev/null and b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00004.png differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00000.png
rename to tests/snapshots/nanosp/test_get_public_key_confirm_refused/00005.png
diff --git a/tests/snapshots/nanosp/test_sign_message/00000.png b/tests/snapshots/nanosp/test_sign_message/00000.png
new file mode 100644
index 0000000..1b27154
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00000.png differ
diff --git a/tests/snapshots/nanosp/test_sign_message/00001.png b/tests/snapshots/nanosp/test_sign_message/00001.png
new file mode 100644
index 0000000..e17b3f6
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00001.png differ
diff --git a/tests/snapshots/nanosp/test_sign_message/00002.png b/tests/snapshots/nanosp/test_sign_message/00002.png
new file mode 100644
index 0000000..64ae294
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00002.png differ
diff --git a/tests/snapshots/nanosp/test_sign_message/00003.png b/tests/snapshots/nanosp/test_sign_message/00003.png
new file mode 100644
index 0000000..639625e
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_message/00003.png differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_sign_message/00004.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00000.png
rename to tests/snapshots/nanosp/test_sign_message/00004.png
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00000.png b/tests/snapshots/nanosp/test_sign_message/00005.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00000.png
rename to tests/snapshots/nanosp/test_sign_message/00005.png
diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00000.png differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00001.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00001.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00001.png
rename to tests/snapshots/nanosp/test_sign_tx_burn_usdt/00001.png
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00002.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00002.png
rename to tests/snapshots/nanosp/test_sign_tx_burn_usdt/00002.png
diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00003.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_burn_usdt/00004.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00000.png differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00001.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00001.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00001.png
rename to tests/snapshots/nanosp/test_sign_tx_confirm/00001.png
diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png
new file mode 100644
index 0000000..cc3d151
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00002.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00003.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png b/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_confirm/00004.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00000.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png
new file mode 100644
index 0000000..3d8fac1
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00001.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png
new file mode 100644
index 0000000..79a7767
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00002.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png
new file mode 100644
index 0000000..d7d0280
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00003.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png
new file mode 100644
index 0000000..de482ce
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00004.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00005.png differ
diff --git a/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png b/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanosp/test_sign_tx_transfer/00006.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png
new file mode 100644
index 0000000..a487005
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png
new file mode 100644
index 0000000..b0fb95c
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png
new file mode 100644
index 0000000..79ec8e7
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00004.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_accepted/00005.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png
new file mode 100644
index 0000000..a487005
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00000.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png
new file mode 100644
index 0000000..b0fb95c
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00001.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png
new file mode 100644
index 0000000..79ec8e7
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00002.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00003.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png
new file mode 100644
index 0000000..c4c84cf
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00004.png differ
diff --git a/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_address_wallet_v3_confirm_refused/00005.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png
new file mode 100644
index 0000000..653262d
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png
new file mode 100644
index 0000000..94681e7
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png
new file mode 100644
index 0000000..9048fa4
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00004.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_accepted/00005.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png
new file mode 100644
index 0000000..653262d
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00000.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png
new file mode 100644
index 0000000..94681e7
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00001.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png
new file mode 100644
index 0000000..9048fa4
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00002.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00003.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png
new file mode 100644
index 0000000..c4c84cf
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00004.png differ
diff --git a/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_get_public_key_confirm_refused/00005.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00000.png b/tests/snapshots/nanox/test_sign_message/00000.png
new file mode 100644
index 0000000..1b27154
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00000.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00001.png b/tests/snapshots/nanox/test_sign_message/00001.png
new file mode 100644
index 0000000..e17b3f6
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00001.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00002.png b/tests/snapshots/nanox/test_sign_message/00002.png
new file mode 100644
index 0000000..64ae294
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00002.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00003.png b/tests/snapshots/nanox/test_sign_message/00003.png
new file mode 100644
index 0000000..639625e
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00003.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00004.png b/tests/snapshots/nanox/test_sign_message/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00004.png differ
diff --git a/tests/snapshots/nanox/test_sign_message/00005.png b/tests/snapshots/nanox/test_sign_message/00005.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_message/00005.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00000.png differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00001.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00001.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_reject/nanox/00001.png
rename to tests/snapshots/nanox/test_sign_tx_burn_usdt/00001.png
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00002.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/burn_reject/nanox/00002.png
rename to tests/snapshots/nanox/test_sign_tx_burn_usdt/00002.png
diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00003.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_burn_usdt/00004.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00000.png b/tests/snapshots/nanox/test_sign_tx_confirm/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00000.png differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00001.png b/tests/snapshots/nanox/test_sign_tx_confirm/00001.png
similarity index 100%
rename from tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00001.png
rename to tests/snapshots/nanox/test_sign_tx_confirm/00001.png
diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00002.png b/tests/snapshots/nanox/test_sign_tx_confirm/00002.png
new file mode 100644
index 0000000..cc3d151
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00002.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00003.png b/tests/snapshots/nanox/test_sign_tx_confirm/00003.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00003.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_confirm/00004.png b/tests/snapshots/nanox/test_sign_tx_confirm/00004.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_confirm/00004.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00000.png b/tests/snapshots/nanox/test_sign_tx_transfer/00000.png
new file mode 100644
index 0000000..487ea10
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00000.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00001.png b/tests/snapshots/nanox/test_sign_tx_transfer/00001.png
new file mode 100644
index 0000000..3d8fac1
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00001.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00002.png b/tests/snapshots/nanox/test_sign_tx_transfer/00002.png
new file mode 100644
index 0000000..79a7767
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00002.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00003.png b/tests/snapshots/nanox/test_sign_tx_transfer/00003.png
new file mode 100644
index 0000000..d7d0280
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00003.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00004.png b/tests/snapshots/nanox/test_sign_tx_transfer/00004.png
new file mode 100644
index 0000000..de482ce
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00004.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00005.png b/tests/snapshots/nanox/test_sign_tx_transfer/00005.png
new file mode 100644
index 0000000..53ae651
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00005.png differ
diff --git a/tests/snapshots/nanox/test_sign_tx_transfer/00006.png b/tests/snapshots/nanox/test_sign_tx_transfer/00006.png
new file mode 100644
index 0000000..a58590b
Binary files /dev/null and b/tests/snapshots/nanox/test_sign_tx_transfer/00006.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png
new file mode 100644
index 0000000..a736b67
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png
new file mode 100644
index 0000000..73fb8df
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png
new file mode 100644
index 0000000..7a49478
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png
new file mode 100644
index 0000000..a736b67
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00000.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png
new file mode 100644
index 0000000..73fb8df
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00001.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png
new file mode 100644
index 0000000..94c91bb
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00002.png differ
diff --git a/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_get_address_wallet_v3_confirm_refused/00003.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png
new file mode 100644
index 0000000..5bd92dd
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00000.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png
new file mode 100644
index 0000000..1419977
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00001.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png
new file mode 100644
index 0000000..fd0228b
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00002.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png
new file mode 100644
index 0000000..7a49478
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_accepted/00003.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png
new file mode 100644
index 0000000..5bd92dd
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00000.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png
new file mode 100644
index 0000000..3fd64e5
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00001.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png
new file mode 100644
index 0000000..94c91bb
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00002.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png
new file mode 100644
index 0000000..3fd64e5
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00003.png differ
diff --git a/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png b/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png
new file mode 100644
index 0000000..94c91bb
Binary files /dev/null and b/tests/snapshots/stax/test_get_public_key_confirm_refused/00004.png differ
diff --git a/tests/snapshots/stax/test_sign_message/00000.png b/tests/snapshots/stax/test_sign_message/00000.png
new file mode 100644
index 0000000..e25d920
Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00000.png differ
diff --git a/tests/snapshots/stax/test_sign_message/00001.png b/tests/snapshots/stax/test_sign_message/00001.png
new file mode 100644
index 0000000..4a1648e
Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00001.png differ
diff --git a/tests/snapshots/stax/test_sign_message/00002.png b/tests/snapshots/stax/test_sign_message/00002.png
new file mode 100644
index 0000000..9dadee7
Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00002.png differ
diff --git a/tests/snapshots/stax/test_sign_message/00003.png b/tests/snapshots/stax/test_sign_message/00003.png
new file mode 100644
index 0000000..cfee3ae
Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00003.png differ
diff --git a/tests/snapshots/stax/test_sign_message/00004.png b/tests/snapshots/stax/test_sign_message/00004.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_message/00004.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png
new file mode 100644
index 0000000..5c40f61
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00000.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png
new file mode 100644
index 0000000..4321aca
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00001.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png
new file mode 100644
index 0000000..06e0ce9
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00002.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png
new file mode 100644
index 0000000..392165d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00003.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png b/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_burn_usdt/00004.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00000.png b/tests/snapshots/stax/test_sign_tx_confirm/00000.png
new file mode 100644
index 0000000..5c40f61
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00000.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00001.png b/tests/snapshots/stax/test_sign_tx_confirm/00001.png
new file mode 100644
index 0000000..f63f311
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00001.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00002.png b/tests/snapshots/stax/test_sign_tx_confirm/00002.png
new file mode 100644
index 0000000..06e0ce9
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00002.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00003.png b/tests/snapshots/stax/test_sign_tx_confirm/00003.png
new file mode 100644
index 0000000..392165d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00003.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_confirm/00004.png b/tests/snapshots/stax/test_sign_tx_confirm/00004.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_confirm/00004.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00000.png b/tests/snapshots/stax/test_sign_tx_transfer/00000.png
new file mode 100644
index 0000000..5c40f61
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00000.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00001.png b/tests/snapshots/stax/test_sign_tx_transfer/00001.png
new file mode 100644
index 0000000..7c1a8f7
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00001.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00002.png b/tests/snapshots/stax/test_sign_tx_transfer/00002.png
new file mode 100644
index 0000000..06e0ce9
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00002.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00003.png b/tests/snapshots/stax/test_sign_tx_transfer/00003.png
new file mode 100644
index 0000000..392165d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00003.png differ
diff --git a/tests/snapshots/stax/test_sign_tx_transfer/00004.png b/tests/snapshots/stax/test_sign_tx_transfer/00004.png
new file mode 100644
index 0000000..f0e072d
Binary files /dev/null and b/tests/snapshots/stax/test_sign_tx_transfer/00004.png differ
diff --git a/tests/speculos/conftest.py b/tests/speculos/conftest.py
deleted file mode 100644
index 469d05b..0000000
--- a/tests/speculos/conftest.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from pathlib import Path
-import pytest
-
-from speculos.client import SpeculosClient
-
-from ledger_client.ledger_cmd import LedgerCommand
-
-
-SCRIPT_DIR = Path(__file__).absolute().parent
-API_URL = "http://127.0.0.1:5000"
-#http://10.66.66.8:5000
-
-
-def pytest_addoption(parser):
- # nanos, nanox, nanosp
- parser.addoption("--model", action="store", default="nanos")
- # qt: default, requires a X server
- # headless: nothing is displayed
- parser.addoption("--display", action="store", default="qt")
-
- path: str = SCRIPT_DIR.parent.parent / "bin" / "app.elf"
- parser.addoption("--path", action="store", default=path)
-
-@pytest.fixture()
-def client(pytestconfig):
- file_path = pytestconfig.getoption("path")
- model = pytestconfig.getoption("model")
-
- args = ['--log-level', 'speculos:DEBUG','--model', model, '--display', pytestconfig.getoption("display")]
- with SpeculosClient(app=str(file_path), args=args) as client:
- yield client
-
-
-@pytest.fixture()
-def cmd(client, pytestconfig):
- yield LedgerCommand(
- client=client,
- debug=True,
- model=pytestconfig.getoption("model"),
- )
\ No newline at end of file
diff --git a/tests/speculos/ledger_client/exception/__init__.py b/tests/speculos/ledger_client/exception/__init__.py
deleted file mode 100644
index acb2bb8..0000000
--- a/tests/speculos/ledger_client/exception/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from .device_exception import DeviceException
-from .errors import (UnknownDeviceError,
- DenyError,
- WrongP1P2Error,
- WrongDataLengthError,
- InsNotSupportedError,
- ClaNotSupportedError,
- WrongResponseLengthError,
- DisplayBip32PathFailError,
- DisplayAddressFailError,
- DisplayAmountFailError,
- WrongTxLengthError,
- TxParsingFailError,
- TxHashFail,
- BadStateError,
- SignatureFailError)
-
-__all__ = [
- "DeviceException",
- "DenyError",
- "UnknownDeviceError",
- "WrongP1P2Error",
- "WrongDataLengthError",
- "InsNotSupportedError",
- "ClaNotSupportedError",
- "WrongResponseLengthError",
- "DisplayBip32PathFailError",
- "DisplayAddressFailError",
- "DisplayAmountFailError",
- "WrongTxLengthError",
- "TxParsingFailError",
- "TxHashFail",
- "BadStateError",
- "SignatureFailError"
-]
diff --git a/tests/speculos/ledger_client/exception/device_exception.py b/tests/speculos/ledger_client/exception/device_exception.py
deleted file mode 100644
index 7cd26f2..0000000
--- a/tests/speculos/ledger_client/exception/device_exception.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import enum
-from typing import Dict, Any, Union
-
-from .errors import *
-
-
-class DeviceException(Exception): # pylint: disable=too-few-public-methods
- exc: Dict[int, Any] = {
- 0x6985: DenyError,
- 0x6A86: WrongP1P2Error,
- 0x6A87: WrongDataLengthError,
- 0x6D00: InsNotSupportedError,
- 0x6E00: ClaNotSupportedError,
- 0xB000: WrongResponseLengthError,
- 0xB001: DisplayBip32PathFailError,
- 0xB002: DisplayAddressFailError,
- 0xB003: DisplayAmountFailError,
- 0xB004: WrongTxLengthError,
- 0xB005: TxParsingFailError,
- 0xB006: TxHashFail,
- 0xB007: BadStateError,
- 0xB008: SignatureFailError
- }
-
- def __new__(cls,
- error_code: int,
- ins: Union[int, enum.IntEnum, None] = None,
- message: str = ""
- ) -> Any:
- error_message: str = (f"Error in {ins!r} command"
- if ins else "Error in command")
-
- if error_code in DeviceException.exc:
- return DeviceException.exc[error_code](hex(error_code),
- error_message,
- message)
-
- return UnknownDeviceError(hex(error_code), error_message, message)
diff --git a/tests/speculos/ledger_client/exception/errors.py b/tests/speculos/ledger_client/exception/errors.py
deleted file mode 100644
index a9a853d..0000000
--- a/tests/speculos/ledger_client/exception/errors.py
+++ /dev/null
@@ -1,58 +0,0 @@
-class UnknownDeviceError(Exception):
- pass
-
-
-class DenyError(Exception):
- pass
-
-
-class WrongP1P2Error(Exception):
- pass
-
-
-class WrongDataLengthError(Exception):
- pass
-
-
-class InsNotSupportedError(Exception):
- pass
-
-
-class ClaNotSupportedError(Exception):
- pass
-
-
-class WrongResponseLengthError(Exception):
- pass
-
-
-class DisplayBip32PathFailError(Exception):
- pass
-
-
-class DisplayAddressFailError(Exception):
- pass
-
-
-class DisplayAmountFailError(Exception):
- pass
-
-
-class WrongTxLengthError(Exception):
- pass
-
-
-class TxParsingFailError(Exception):
- pass
-
-
-class TxHashFail(Exception):
- pass
-
-
-class BadStateError(Exception):
- pass
-
-
-class SignatureFailError(Exception):
- pass
diff --git a/tests/speculos/ledger_client/ledger_cmd.py b/tests/speculos/ledger_client/ledger_cmd.py
deleted file mode 100644
index b732c32..0000000
--- a/tests/speculos/ledger_client/ledger_cmd.py
+++ /dev/null
@@ -1,155 +0,0 @@
-from ast import List
-from contextlib import contextmanager
-import struct
-from time import sleep
-from typing import Tuple
-
-from speculos.client import SpeculosClient, ApduException
-
-from ledger_client.ledger_cmd_builder import LedgerCommandBuilder, InsType, WalletType
-from ledger_client.exception import DeviceException
-
-
-class LedgerCommand:
- def __init__(self,
- client: SpeculosClient,
- debug: bool = False,
- model: str = "nanos") -> None:
- self.client = client
- self.builder = LedgerCommandBuilder(debug=debug)
- self.debug = debug
- self.model = model
-
- def get_configuration(self) -> Tuple[ int, int, int]:
- try:
- response = self.client._apdu_exchange(
- self.builder.get_configuration()
- ) # type: int, bytes
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_VERSION)
- # response = MAJOR (1) || MINOR (1) || PATCH (1)
- assert len(response) == 3
- major, minor, patch = struct.unpack(
- "BBB",
- response
- ) # type: int, int, int
-
- return major, minor, patch
-
- def get_public_key(self, account: int, display: bool = False) -> str:
- try:
- response = self.client._apdu_exchange(
- self.builder.get_public_key(account=account, display=display)
- ) # type: bytes
-
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_PUBLIC_KEY)
-
- # response = pub_key_len (1) ||
- # pub_key (var)
- offset: int = 0
-
- pub_key_len: int = response[offset]
-
- offset += 1
- pubkey = response[offset:].hex()
-
- assert len(response) == 1 + pub_key_len
-
- return pubkey
-
- @contextmanager
- def get_public_key_with_display(self, account: int, result: List, display: bool = False) -> Tuple[bytes, bytes]:
-
- try:
- chunk: bytes = self.builder.get_public_key(account=account, display=display)
-
- with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1],
- p1=chunk[2], p2=chunk[3],
- data=chunk[5:]) as exchange:
- yield exchange
-
- response: bytes = exchange.receive()
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_PUBLIC_KEY)
- offset: int = 0
-
- pub_key_len: int = response[offset]
-
- offset += 1
- pubkey = response[offset:].hex()
- assert len(response) == 1 + pub_key_len
- print("PUBKEY", pubkey)
- result.append(pubkey)
-
- def get_address(self, account: int, wallet_type: int, display: bool = False) -> str:
- try:
- response = self.client._apdu_exchange(
- self.builder.get_address(account=account, wallet_type=wallet_type, display=display)
- ) # type: bytes
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_GET_ADDRESS)
-
- offset: int = 0
-
- addr_len: int = response[offset]
-
- offset += 1
- address = response[offset:].hex()
-
- assert len(response) == 1 + addr_len
-
- return address
-
- @contextmanager
- def sign_message(self, res: List, account: int, message: bytes) -> Tuple[bytes]:
- try:
- chunk: bytes = self.builder.sign_message(account=account, message=message)
-
- with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1],
- p1=chunk[2], p2=chunk[3],
- data=chunk[5:]) as exchange:
- yield exchange
-
- response: bytes = exchange.receive()
-
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN)
-
- offset: int = 0
- signature_len: int = response[offset]
- assert signature_len == 64
-
- offset += 1
- signature = response[offset:]
- assert len(response) == 1 + signature_len
-
- res.append(signature)
-
-
- @contextmanager
- def sign_tx(self, res: List, account: int, wallet_type: int, decimals: int, ticker: str, meta: struct, data: bytes) -> Tuple[bytes]:
- try:
- chunk: bytes = self.builder.sign_tx(
- account=account, wallet_type=wallet_type, decimals=decimals, ticker=ticker, meta=meta, data=data)
-
- with self.client.apdu_exchange_nowait(cla=chunk[0], ins=chunk[1],
- p1=chunk[2], p2=chunk[3],
- data=chunk[5:]) as exchange:
- yield exchange
-
- response: bytes = exchange.receive()
-
- except ApduException as error:
- raise DeviceException(error_code=error.sw, ins=InsType.INS_SIGN_TX)
-
- offset: int = 0
- signature_len: int = response[offset]
- assert signature_len == 64
-
- offset += 1
- signature = response[offset:]
- assert len(response) == 1 + signature_len
-
- res.append(signature)
-
diff --git a/tests/speculos/ledger_client/ledger_cmd_builder.py b/tests/speculos/ledger_client/ledger_cmd_builder.py
deleted file mode 100644
index 238acc6..0000000
--- a/tests/speculos/ledger_client/ledger_cmd_builder.py
+++ /dev/null
@@ -1,243 +0,0 @@
-import enum
-import logging
-import struct
-from typing import List, Tuple, Union, Iterator, cast
-
-from ledger_client.transaction import EIP712, PersonalTransaction, Transaction
-#from ethereum_client.plugin import ERC20Information, Plugin
-from ledger_client.utils import packed_bip32_path_from_string
-
-MAX_APDU_LEN: int = 255
-
-def chunked(size, source):
- for i in range(0, len(source), size):
- yield source[i:i+size]
-
-def chunkify(data: bytes, chunk_len: int) -> Iterator[Tuple[bool, bytes]]:
- size: int = len(data)
-
- if size <= chunk_len:
- yield True, data
- return
-
- chunk: int = size // chunk_len
- remaining: int = size % chunk_len
- offset: int = 0
-
- for i in range(chunk):
- yield False, data[offset:offset + chunk_len]
- offset += chunk_len
-
- if remaining:
- yield True, data[offset:]
-
-class InsType(enum.IntEnum):
- INS_GET_PUBLIC_KEY = 0x02
- INS_GET_CONFIGURATION = 0x01
- INS_SIGN = 0x03
- INS_GET_ADDRESS = 0x04
- INS_SIGN_TX = 0x05
-
-
-class WalletType(enum.IntEnum):
- WalletV3 = 0,
- EverWallet = 1,
- SafeMultisig = 2,
- SafeMultisig24h = 3,
- SetcodeMultisig = 4,
- BridgeMultisig = 5,
- Surf = 6,
- Multisig2 = 7,
- Multisig2_1 = 8,
-
-
-class LedgerCommandBuilder:
- """APDU command builder for the Boilerplate application.
-
- Parameters
- ----------
- debug: bool
- Whether you want to see logging or not.
-
- Attributes
- ----------
- debug: bool
- Whether you want to see logging or not.
-
- """
- CLA: int = 0xE0
-
- def __init__(self, debug: bool = False):
- """Init constructor."""
- self.debug = debug
-
- def serialize(self,
- cla: int,
- ins: Union[int, enum.IntEnum],
- p1: int = 0,
- p2: int = 0,
- cdata: bytes = b"") -> bytes:
- """Serialize the whole APDU command (header + data).
-
- Parameters
- ----------
- cla : int
- Instruction class: CLA (1 byte)
- ins : Union[int, IntEnum]
- Instruction code: INS (1 byte)
- p1 : int
- Instruction parameter 1: P1 (1 byte).
- p2 : int
- Instruction parameter 2: P2 (1 byte).
- cdata : bytes
- Bytes of command data.
-
- Returns
- -------
- bytes
- Bytes of a complete APDU command.
-
- """
- ins = cast(int, ins.value) if isinstance(ins, enum.IntEnum) else cast(int, ins)
-
- header: bytes = struct.pack("BBBBB",
- cla,
- ins,
- p1,
- p2,
- len(cdata)) # add Lc to APDU header
-
- if self.debug:
- logging.info("header: %s", header.hex())
- logging.info("cdata: %s", cdata.hex())
-
- print("serialize INS=", ins)
- print("serialize DATA= ", cdata.hex())
- return header + cdata
-
- def get_configuration(self) -> bytes:
- """Command builder for GET_CONFIGURATON
-
- Returns
- -------
- bytes
- APDU command for GET_CONFIGURATON
-
- """
- return self.serialize(cla=self.CLA,
- ins=InsType.INS_GET_CONFIGURATION,
- p1=0x00,
- p2=0x00,
- cdata=b"")
-
-
- def get_public_key(self, account: int, display: bool = False) -> bytes:
- """Command builder for GET_PUBLIC_KEY.
-
- Parameters
- ----------
- bip32_path: str
- String representation of BIP32 path.
- display : bool
- Whether you want to display the address on the device.
-
- Returns
- -------
- bytes
- APDU command for GET_PUBLIC_KEY.
-
- """
- cdata = account.to_bytes(4, byteorder='big')
- print("cdata= ", cdata)
- return self.serialize(cla=self.CLA,
- ins=InsType.INS_GET_PUBLIC_KEY,
- p1=0x01 if display else 0x00,
- p2=0x00,
- cdata=cdata)
-
- def get_address(self, account: int, wallet_type: int, display: bool) -> bytes:
- """Command builder for GET_ADDRESS.
-
- Parameters
- ----------
- account: int
- Account identifier.
- wallet_type: int
- Wallet type.
- display : bool
- Whether you want to display the address on the device.
-
- Returns
- -------
- bytes
- APDU command for GET_ADDRESS.
-
- """
-
- #account_num = account.to_bytes(4, byteorder='big')
-
- #wallet = wallet_type.to_bytes(1, byteorder='big')
-
- cdata = (account.to_bytes(4, byteorder='big') + wallet_type.to_bytes(1, byteorder='big'))
- #cdata = (account_num + wallet)
-
- return self.serialize(cla=self.CLA,
- ins=InsType.INS_GET_ADDRESS,
- p1=0x01 if display else 0x00,
- p2=0x00,
- cdata=cdata)
-
- def sign_message(self, account: int, message: bytes) -> bytes:
- """Command builder for SIGN_MESSAGE.
-
- Parameters
- ----------
- account: int
- Account identifier.
- message: str
- Message hash.
- display : bool
- Whether you want to display the address on the device.
-
- Returns
- -------
- bytes
- APDU command for SIGN_MESSAGE.
-
- """
-
- cdata = (account.to_bytes(4, byteorder='big') + message)
-
- return self.serialize(cla=self.CLA,
- ins=InsType.INS_SIGN,
- p1=0x01,
- p2=0x00,
- cdata=cdata)
-
- def sign_tx(self, account: int, wallet_type: int, decimals: int, ticker: str, meta: struct, data: bytes) -> bytes:
- """Command builder for INS_SIGN_TX.
-
- Parameters
- ----------
- bip32_path : str
- String representation of BIP32 path.
- transaction : Transaction
- Representation of the transaction to be signed.
-
- Yields
- -------
- bytes
- APDU command chunk for INS_SIGN_TX.
-
- """
- meta_data = 0
- cdata = (account.to_bytes(4, byteorder='big') + wallet_type.to_bytes(1, byteorder='big')
- + decimals.to_bytes(1, byteorder='big') + len(ticker).to_bytes(1, byteorder='big')
- + bytes(ticker, 'UTF-8') + meta_data.to_bytes(1, byteorder='big') + data)
-
- return self.serialize(cla=self.CLA,
- ins=InsType.INS_SIGN_TX,
- p1=0x01,
- p2=0x00,
- cdata=cdata)
-
diff --git a/tests/speculos/ledger_client/transaction.py b/tests/speculos/ledger_client/transaction.py
deleted file mode 100644
index 8186cec..0000000
--- a/tests/speculos/ledger_client/transaction.py
+++ /dev/null
@@ -1,96 +0,0 @@
-from typing import Union
-
-from ledger_client.utils import write_varint, UINT64_MAX
-
-
-class TransactionError(Exception):
- pass
-
-EIP2930 = 1
-EIP1559 = 2
-
-class PersonalTransaction:
- def __init__(self, msg: Union[str, bytes]) -> None:
- # If you want to send bytes directly you have to put "0x" before the string
- if msg[0:2] == "0x":
- self.msg: bytes = bytes.fromhex(msg[2:])
- else:
- self.msg: bytes = bytes(msg, "utf-8")
-
- def serialize(self) -> bytes:
- return b"".join([
- len(self.msg).to_bytes(4, byteorder="big"),
- self.msg,
- ])
-
-class Transaction:
- def __init__(self, txType: int, nonce: int, gasPrice: int, gasLimit: int, to: Union[str, bytes], value: int, data: Union[str, bytes] = "", chainID: int = -1) -> None:
- self.txType: int = txType
- self.nonce: int = nonce
- self.gasPrice: int = gasPrice
- self.gasLimit: int = gasLimit
- self.to: bytes = bytes.fromhex(to[2:]) if isinstance(to, str) else to
- self.value: int = value
- self.data: bytes = bytes(data, "utf-8")
- self.chainID = b''
-
- if not (0 <= self.nonce <= UINT64_MAX):
- raise TransactionError(f"Bad nonce: '{self.nonce}'!")
-
- if not (0 <= self.value <= UINT64_MAX):
- raise TransactionError(f"Bad value: '{self.value}'!")
-
- if len(self.to) != 20:
- raise TransactionError(f"Bad address: '{self.to}'!")
-
- self.lenNonce = int((len(hex(self.nonce)) - 1) / 2)
- self.lenGP = int((len(hex(self.gasPrice)) - 1) / 2)
- self.lenGL = int((len(hex(self.gasLimit)) - 1) / 2)
- self.lenValue = int((len(hex(self.value)) - 1) / 2)
-
- self.lenChainID = int((len(hex(chainID)) - 1) / 2)
-
- if chainID != -1:
- self.chainID = b"".join([
- b'' if self.lenChainID == 1 else (self.lenChainID + 0x80).to_bytes(1, byteorder="big"),
- chainID.to_bytes(self.lenChainID, byteorder="big"),
- write_varint(0 + 0x80),
- write_varint(0 + 0x80),
- ])
-
- def serialize(self) -> bytes:
- return b"".join([
- self.txType.to_bytes(1, byteorder="big"),
-
- b'' if self.lenNonce == 1 else write_varint(self.lenNonce + 0x80),
- self.nonce.to_bytes(self.lenNonce, byteorder="big"),
-
- write_varint(self.lenGP + 0x80),
- self.gasPrice.to_bytes(self.lenGP, byteorder="big"),
-
- write_varint(self.lenGL + 0x80),
- self.gasLimit.to_bytes(self.lenGL, byteorder="big"),
-
- write_varint(len(self.to) + 0x80),
- self.to,
-
- write_varint(self.lenValue + 0x80),
- self.value.to_bytes(self.lenValue, byteorder="big"),
-
- write_varint(len(self.data) + 0x80),
- self.data,
-
- self.chainID,
-
- ])
-
-class EIP712:
- def __init__(self, domain_hash: str, msg_hash: str) -> None:
- self.domain_hash = bytes.fromhex(domain_hash)
- self.msg_hash = bytes.fromhex(msg_hash)
-
- def serialize(self) -> bytes:
- return b"".join([
- self.domain_hash,
- self.msg_hash
- ])
\ No newline at end of file
diff --git a/tests/speculos/ledger_client/utils.py b/tests/speculos/ledger_client/utils.py
deleted file mode 100644
index aa7bd96..0000000
--- a/tests/speculos/ledger_client/utils.py
+++ /dev/null
@@ -1,115 +0,0 @@
-from io import BytesIO
-from typing import List, Optional, Literal, Tuple
-import PIL.Image as Image
-
-import speculos.client
-
-UINT64_MAX: int = 18446744073709551615
-UINT32_MAX: int = 4294967295
-UINT16_MAX: int = 65535
-
-# Association tableau si écran nanos ou nanox
-PATH_IMG = {"nanos": "nanos", "nanox": "nanox", "nanosp": "nanosp"}
-
-def save_screenshot(cmd, path: str):
- screenshot = cmd.client.get_screenshot()
- img = Image.open(BytesIO(screenshot))
- img.save(path)
-
-
-def compare_screenshot(cmd, path: str):
- screenshot = cmd.client.get_screenshot()
- assert speculos.client.screenshot_equal(path, BytesIO(screenshot))
-
-
-def parse_sign_response(response : bytes) -> Tuple[bytes, bytes, bytes]:
- assert len(response) == 65
-
- offset: int = 0
-
- v: bytes = response[offset]
- offset += 1
-
- r: bytes = response[offset:offset + 32]
- offset += 32
-
- s: bytes = response[offset:]
-
- return (v, r, s)
-
-
-def bip32_path_from_string(path: str) -> List[bytes]:
- splitted_path: List[str] = path.split("/")
-
- if not splitted_path:
- raise Exception(f"BIP32 path format error: '{path}'")
-
- if "m" in splitted_path and splitted_path[0] == "m":
- splitted_path = splitted_path[1:]
-
- return [int(p).to_bytes(4, byteorder="big") if "'" not in p
- else (0x80000000 | int(p[:-1])).to_bytes(4, byteorder="big")
- for p in splitted_path]
-
-
-def packed_bip32_path_from_string(path: str) -> bytes:
- bip32_paths = bip32_path_from_string(path)
-
- return b"".join([
- len(bip32_paths).to_bytes(1, byteorder="big"),
- *bip32_paths
- ])
-
-
-def write_varint(n: int) -> bytes:
- if n < 0xFC:
- return n.to_bytes(1, byteorder="little")
-
- if n <= UINT16_MAX:
- return b"\xFD" + n.to_bytes(2, byteorder="little")
-
- if n <= UINT32_MAX:
- return b"\xFE" + n.to_bytes(4, byteorder="little")
-
- if n <= UINT64_MAX:
- return b"\xFF" + n.to_bytes(8, byteorder="little")
-
- raise ValueError(f"Can't write to varint: '{n}'!")
-
-
-def read_varint(buf: BytesIO,
- prefix: Optional[bytes] = None) -> int:
- b: bytes = prefix if prefix else buf.read(1)
-
- if not b:
- raise ValueError(f"Can't read prefix: '{b}'!")
-
- n: int = {b"\xfd": 2, b"\xfe": 4, b"\xff": 8}.get(b, 1) # default to 1
-
- b = buf.read(n) if n > 1 else b
-
- if len(b) != n:
- raise ValueError("Can't read varint!")
-
- return int.from_bytes(b, byteorder="little")
-
-
-def read(buf: BytesIO, size: int) -> bytes:
- b: bytes = buf.read(size)
-
- if len(b) < size:
- raise ValueError(f"Cant read {size} bytes in buffer!")
-
- return b
-
-
-def read_uint(buf: BytesIO,
- bit_len: int,
- byteorder: Literal['big', 'little'] = 'little') -> int:
- size: int = bit_len // 8
- b: bytes = buf.read(size)
-
- if len(b) < size:
- raise ValueError(f"Can't read u{bit_len} in buffer!")
-
- return int.from_bytes(b, byteorder)
diff --git a/tests/speculos/requirements.txt b/tests/speculos/requirements.txt
deleted file mode 100644
index 343948d..0000000
--- a/tests/speculos/requirements.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-speculos
-ed25519
-pytest>=6.1.1,<7.0.0
-ledgercomm>=1.1.0,<1.2.0
-ecdsa>=0.16.1,<0.17.0
-pysha3>=1.0.0,<2.0.0
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png
deleted file mode 100644
index fdc04e7..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png
deleted file mode 100644
index a1e51e9..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png
deleted file mode 100644
index 7a7214c..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png
deleted file mode 100644
index 660f665..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png b/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png
deleted file mode 100644
index e7a5819..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanos/00005.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png
deleted file mode 100644
index 029ed0a..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png
deleted file mode 100644
index 9dfa9f8..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png
deleted file mode 100644
index 5fd127e..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png
deleted file mode 100644
index f445d03..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png
deleted file mode 100644
index 739d0b1..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png b/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png
deleted file mode 100644
index 5fd127e..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/approve/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png
deleted file mode 100644
index fdc04e7..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png
deleted file mode 100644
index a1e51e9..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png
deleted file mode 100644
index 7a7214c..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png b/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png
deleted file mode 100644
index 660f665..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png
deleted file mode 100644
index 029ed0a..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png
deleted file mode 100644
index 9dfa9f8..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png
deleted file mode 100644
index f445d03..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png b/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png
deleted file mode 100644
index 739d0b1..0000000
Binary files a/tests/speculos/screenshots/get_pubkey/reject/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00000.png b/tests/speculos/screenshots/sign/sign_message/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00001.png b/tests/speculos/screenshots/sign/sign_message/nanos/00001.png
deleted file mode 100644
index d369d6c..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00002.png b/tests/speculos/screenshots/sign/sign_message/nanos/00002.png
deleted file mode 100644
index 1743761..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00003.png b/tests/speculos/screenshots/sign/sign_message/nanos/00003.png
deleted file mode 100644
index 56201e2..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00004.png b/tests/speculos/screenshots/sign/sign_message/nanos/00004.png
deleted file mode 100644
index 8ae711b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00005.png b/tests/speculos/screenshots/sign/sign_message/nanos/00005.png
deleted file mode 100644
index f4fd25b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00005.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanos/00006.png b/tests/speculos/screenshots/sign/sign_message/nanos/00006.png
deleted file mode 100644
index 68927d6..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanos/00006.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png
deleted file mode 100644
index 4e2a997..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png
deleted file mode 100644
index 7a4bd19..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png
deleted file mode 100644
index e52854f..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png
deleted file mode 100644
index fdc3d3b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png
deleted file mode 100644
index fdc3d3b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00005.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png b/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png
deleted file mode 100644
index fdc3d3b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanosp/00006.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00000.png b/tests/speculos/screenshots/sign/sign_message/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00001.png b/tests/speculos/screenshots/sign/sign_message/nanox/00001.png
deleted file mode 100644
index 4e2a997..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00002.png b/tests/speculos/screenshots/sign/sign_message/nanox/00002.png
deleted file mode 100644
index 7a4bd19..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00003.png b/tests/speculos/screenshots/sign/sign_message/nanox/00003.png
deleted file mode 100644
index e52854f..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00004.png b/tests/speculos/screenshots/sign/sign_message/nanox/00004.png
deleted file mode 100644
index 2cca50c..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00005.png b/tests/speculos/screenshots/sign/sign_message/nanox/00005.png
deleted file mode 100644
index fdc3d3b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00005.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_message/nanox/00006.png b/tests/speculos/screenshots/sign/sign_message/nanox/00006.png
deleted file mode 100644
index fdc3d3b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_message/nanox/00006.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png
deleted file mode 100644
index d369d6c..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png
deleted file mode 100644
index 1743761..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png
deleted file mode 100644
index 56201e2..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png
deleted file mode 100644
index 8ae711b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png b/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png
deleted file mode 100644
index f4fd25b..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanos/00005.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png
deleted file mode 100644
index 4e2a997..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png
deleted file mode 100644
index 7a4bd19..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png
deleted file mode 100644
index e52854f..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png
deleted file mode 100644
index 4e2a997..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png
deleted file mode 100644
index 7a4bd19..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png b/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png
deleted file mode 100644
index e52854f..0000000
Binary files a/tests/speculos/screenshots/sign/sign_reject/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png
deleted file mode 100644
index 308a1ab..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png
deleted file mode 100644
index 9ef8a57..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png
deleted file mode 100644
index 1c9156c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png
deleted file mode 100644
index 9c7e704..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png
deleted file mode 100644
index c922246..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanosp/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png b/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png
deleted file mode 100644
index e90cd9d..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_reject/nanox/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png
deleted file mode 100644
index 308a1ab..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png
deleted file mode 100644
index 9ef8a57..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png
deleted file mode 100644
index 1c9156c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png
deleted file mode 100644
index c26449c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png
deleted file mode 100644
index 96a5cae..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png
deleted file mode 100644
index c26449c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png
deleted file mode 100644
index 96a5cae..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/burn_tx/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png
deleted file mode 100644
index 235fddd..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png
deleted file mode 100644
index 1370858..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png
deleted file mode 100644
index 1c9156c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png
deleted file mode 100644
index 24c4f84..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png
deleted file mode 100644
index 24c4f84..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_confirm_tx/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png
deleted file mode 100644
index ce795f3..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png
deleted file mode 100644
index 235fddd..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png
deleted file mode 100644
index 1370858..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png
deleted file mode 100644
index 1c9156c..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png
deleted file mode 100644
index 9c7e704..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanos/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png
deleted file mode 100644
index 0186ef4..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png
deleted file mode 100644
index 24c4f84..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png
deleted file mode 100644
index c922246..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanosp/00004.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png
deleted file mode 100644
index 6578872..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00000.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png
deleted file mode 100644
index 0186ef4..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00001.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png
deleted file mode 100644
index 24c4f84..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00002.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png
deleted file mode 100644
index 570ce28..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00003.png and /dev/null differ
diff --git a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png b/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png
deleted file mode 100644
index e90cd9d..0000000
Binary files a/tests/speculos/screenshots/sign_tx/sign_reject_tx/nanox/00004.png and /dev/null differ
diff --git a/tests/speculos/test_address.py b/tests/speculos/test_address.py
deleted file mode 100644
index 0e7a1f5..0000000
--- a/tests/speculos/test_address.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from time import sleep
-
-from ledger_client.ledger_cmd_builder import WalletType
-
-def test_address(cmd):
- sleep(0.5)
- # True = verify address, False = skip display verification
- # Test with Wallet v3
- assert cmd.get_address(0, WalletType.WalletV3, False) == "7571b498e3fed7a0fffbe21377e50548c92da4a04842e1b163547d3e8980cf64"
- # Test with Everwallet
- assert cmd.get_address(0, WalletType.EverWallet, False) == "522a4cc774797f537c41b4853a9b83f359fe2802a5cf3bd9f31240c495e82358"
- # Test with SafeMultisig
- assert cmd.get_address(0, WalletType.SafeMultisig, False) == "ae990783e06a196ab03029fe4517dda0ea318c091cd49ff51cc0a40369b0aff5"
- # Test with SafeMultisig24h
- assert cmd.get_address(0, WalletType.SafeMultisig24h, False) == "98135fb68e91833e810122abfe00ff3b38c1d555bf773741f869dea8b87fb72d"
- # Test with SetcodeMultisig
- assert cmd.get_address(0, WalletType.SetcodeMultisig, False) == "23e76dee54e3f715e11cf374177e786878814ad2c7ac6e38bc06515efdb5fab3"
- # Test with BridgeMultisig
- assert cmd.get_address(0, WalletType.BridgeMultisig, False) == "0806dbe6c4581af1165879fd196d3e02404029540e818921edfedbffb46d3c65"
- # Test with Surf
- assert cmd.get_address(0, WalletType.Surf, False) == "ec03eb7af13d70083b9f3c8202b0321ede255edc624292c531106f50d9f005b3"
- # Test with Multisig2
- assert cmd.get_address(0, WalletType.Multisig2, False) == "9760a1b7393cdbb389205f72ebf4d7e362b06b419fdac9aeccd83bf39ce0d05a"
- # Test with Multisig2_1
- assert cmd.get_address(0, WalletType.Multisig2_1, False) == "1de569744cf341d8e2e35996f23cdf5d5f9226c1400c98100f480d89e70c6bcf"
-
-
-
-
-
-
-
-
-
diff --git a/tests/speculos/test_configuration.py b/tests/speculos/test_configuration.py
deleted file mode 100644
index 3eb42e2..0000000
--- a/tests/speculos/test_configuration.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from time import sleep
-
-def test_configuration(cmd):
- sleep(0.5)
- if cmd.model == "nanos":
- assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch
- if cmd.model == "nanox":
- assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch
- if cmd.model == "nanosp":
- assert cmd.get_configuration() == (1, 0, 10) #major, minor, patch
\ No newline at end of file
diff --git a/tests/speculos/test_pubkey.py b/tests/speculos/test_pubkey.py
deleted file mode 100644
index 01c5123..0000000
--- a/tests/speculos/test_pubkey.py
+++ /dev/null
@@ -1,80 +0,0 @@
-from time import sleep
-
-import pytest
-
-import ledger_client
-from ledger_client.utils import compare_screenshot, save_screenshot, PATH_IMG
-
-
-def test_get_public_key_simple(cmd):
-
- # without display
- public_key = cmd.get_public_key(account=0, display=False)
-
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
-
-def test_get_public_key(cmd):
-
- # without display
- result: list = []
- with cmd.get_public_key_with_display(account=0, display=False, result=result) as exchange:
- pass
-
- public_key = result[0]
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- # with display
- result: list = []
- with cmd.get_public_key_with_display(account=0, display=True, result=result) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00005.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox" or cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/approve/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- public_key1 = result[0]
- assert public_key1 == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
-
-def test_get_public_key_reject(cmd):
-
- result: list = []
- with pytest.raises(ledger_client.exception.errors.DenyError) as error:
- with cmd.get_public_key_with_display(account=0, display=True, result=result) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
-
- if cmd.model == "nanox" or cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/get_pubkey/reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('both')
- assert error.value.args[0] == '0x6985'
\ No newline at end of file
diff --git a/tests/speculos/test_sign_message.py b/tests/speculos/test_sign_message.py
deleted file mode 100644
index 56b6e20..0000000
--- a/tests/speculos/test_sign_message.py
+++ /dev/null
@@ -1,144 +0,0 @@
-from time import sleep
-import ed25519
-import pytest
-import ledger_client
-from ledger_client.utils import save_screenshot, compare_screenshot, PATH_IMG
-
-SIGN_MAGIC: [4] = [0xFF, 0xFF, 0xFF, 0xFF]
-
-SUCCESS = 0x9000
-
-
-def test_sign(cmd):
- sleep(0.5)
-
- account = 0
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
-
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- hash = "c617baa256c79192029d57bf8cce9a0dccd57923faf395e399fe04a4d05ed71d"
- hash_in_bytes = bytes.fromhex(hash)
- assert len(hash_in_bytes) == 32
-
- prefix = bytes(SIGN_MAGIC)
- assert len(prefix) == 4
- message = prefix + hash_in_bytes
-
- res: list = []
- # an acc num | bytes to sign
- with cmd.sign_message(res, account, hash_in_bytes) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00005.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00006.png")
- cmd.client.press_and_release('both')
-
- if cmd.model == "nanox":
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
-
- if cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00005.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_message/{PATH_IMG[cmd.model]}/00006.png")
- cmd.client.press_and_release('both')
-
- signature = res[0]
- assert len(signature) == 64
-
- verifying_key = ed25519.VerifyingKey(public_key, encoding="hex")
- result = 0
- try:
- verifying_key.verify(signature, message)
- result = SUCCESS
- print("The signature is valid.")
- except ed25519.BadSignatureError:
- print("Invalid signature!")
-
- assert result == SUCCESS
-
-def test_sign_reject(cmd):
- sleep(0.5)
- account = 0
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- hash = "c617baa256c79192029d57bf8cce9a0dccd57923faf395e399fe04a4d05ed71d"
- hash_in_bytes = bytes.fromhex(hash)
- assert len(hash_in_bytes) == 32
-
- prefix = bytes(SIGN_MAGIC)
- assert len(prefix) == 4
- message = prefix + hash_in_bytes
-
- res: list = []
- # an acc num | bytes to sign
- with pytest.raises(ledger_client.exception.errors.DenyError) as error:
- if cmd.model == "nanos":
- with cmd.sign_message(res, account, hash_in_bytes) as exchange:
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00005.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox":
- with cmd.sign_message(res, account, hash_in_bytes) as exchange:
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanosp":
- with cmd.sign_message(res, account, hash_in_bytes) as exchange:
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign/sign_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- assert error.value.args[0] == '0x6985'
-
-
diff --git a/tests/speculos/test_sign_tx.py b/tests/speculos/test_sign_tx.py
deleted file mode 100644
index d4a8987..0000000
--- a/tests/speculos/test_sign_tx.py
+++ /dev/null
@@ -1,243 +0,0 @@
-from time import sleep
-import ed25519
-import pytest
-import ledger_client
-from ledger_client.ledger_cmd_builder import WalletType
-from dataclasses import dataclass
-import base64
-from ledger_client.utils import save_screenshot, compare_screenshot, PATH_IMG
-
-SIGN_MAGIC: [4] = [0xFF, 0xFF, 0xFF, 0xFF]
-
-SUCCESS = 0x9000
-
-EVER_DECIMALS: int = 9
-EVER_TICKER: str = "EVER"
-USDT_DECIMALS: int = 9
-USDT_TICKER: str = "USDT"
-WALLET_ID: int = 0x4BA92D8A
-DEFAULT_EXPIRATION_TIMEOUT: int = 60
-
-class SignTransactionMeta:
- chain_id: int
- workchain_id: int
- current_wallet_type: WalletType
-
-
-def test_sign_tx(cmd):
-
- account = 0
- wallet_type = WalletType.SafeMultisig
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- message = "te6ccgEBAQEAOwAAcfDmnGpQVUZxL24fHgfUfLGp2/wzR+YWmZukQraxETyqAAAAxHF5r4KyShssDVOgdrJKGvzpVh6gwA=="
- boc = base64.b64decode(message)
- hash = "1ce8d3bd135bdc9b5538e086643e06eb74ebf6aed06161a14b19bd6abcb602ec"
-
- sign_transaction_meta = SignTransactionMeta()
-
- res: list = []
- with cmd.sign_tx(res, account, wallet_type, EVER_DECIMALS, EVER_TICKER, 0, boc[4:]) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_confirm_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- signature = res[0]
-
- print("SIGNATURE =", signature)
- verifying_key = ed25519.VerifyingKey(public_key, encoding="hex")
- result = 0
- try:
- verifying_key.verify(signature, bytes.fromhex(hash))
- result = SUCCESS
- print("The signature is valid.")
- except ed25519.BadSignatureError:
- print("Invalid signature!")
-
- assert result == SUCCESS
-
-
-def test_burn_tx(cmd):
- sleep(0.5)
-
- account = 0
- wallet_type = WalletType.SafeMultisig
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- message = "te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA=";
- boc = base64.b64decode(message)
- hash = "1675cfae267250459cee3ccbc1f559322f24f6d0fde33b1b3141f9498a7e4b89"
-
- sign_transaction_meta = SignTransactionMeta()
-
- res: list = []
- with cmd.sign_tx(res, account, wallet_type, USDT_DECIMALS, USDT_TICKER, 0, boc[4:]) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('both')
- signature = res[0]
- verifying_key = ed25519.VerifyingKey(public_key, encoding="hex")
- result = 0
- try:
- verifying_key.verify(signature, bytes.fromhex(hash))
- result = SUCCESS
- print("The signature is valid.")
- except ed25519.BadSignatureError:
- print("Invalid signature!")
-
- assert result == SUCCESS
-
-
-def test_burn_tx_reject(cmd):
- sleep(0.5)
- account = 0
- wallet_type = WalletType.SafeMultisig
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- message = "te6ccgEBBQEAyQABYbO621NdG4jQ5NYNMWVnsUSFaO+v3yGEbs0LoC462r+XAAAAxHGxjJEySil5CY7BZsABAWOAG+Ilaz1wTyTEauoymMGl6o+NGqhszIlHS8BXAmXniYrAAAAAAAAAAAA202lAb5VWNAIBa1YlSK0AAAAAAAAAAAAAAABJUE+AgBXkJWs9cE8kxGrqMpjBpeqPjRqobMyJR0vAVwJl54mK0AMBQ4AX5CVrPXBPJMRq6jKYwaXqj40aqGzMiUdLwFcCZeeJitAEAAA=";
- boc = base64.b64decode(message)
- res: list = []
- with pytest.raises(ledger_client.exception.errors.DenyError) as error:
-
- with cmd.sign_tx(res, account, wallet_type, USDT_DECIMALS, USDT_TICKER, 0, boc[4:]) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/burn_reject/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- assert error.value.args[0] == '0x6985'
-
-
-def test_sign_tx_reject(cmd):
-
- account = 0
- wallet_type = WalletType.SafeMultisig
- # # # getting pubkey
- public_key = cmd.get_public_key(account=0, display=False)
- assert public_key == "3099f14eccaa0542d2d60e92eb66495f6ecf01a114e12f9db8d9cb827a87bf84"
-
- message = "te6ccgEBAQEAOwAAcfDmnGpQVUZxL24fHgfUfLGp2/wzR+YWmZukQraxETyqAAAAxHF5r4KyShssDVOgdrJKGvzpVh6gwA=="
- boc = base64.b64decode(message)
- hash = "1ce8d3bd135bdc9b5538e086643e06eb74ebf6aed06161a14b19bd6abcb602ec"
-
- sign_transaction_meta = SignTransactionMeta()
-
- res: list = []
- with pytest.raises(ledger_client.exception.errors.DenyError) as error:
- with cmd.sign_tx(res, account, wallet_type, EVER_DECIMALS, EVER_TICKER, 0, boc[4:]) as exchange:
- if cmd.model == "nanos":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanox":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- if cmd.model == "nanosp":
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00000.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00001.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00002.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00003.png")
- cmd.client.press_and_release('right')
- compare_screenshot(cmd, f"screenshots/sign_tx/sign_reject_tx/{PATH_IMG[cmd.model]}/00004.png")
- cmd.client.press_and_release('both')
- assert error.value.args[0] == '0x6985'
-
diff --git a/tests/test_address_cmd.py b/tests/test_address_cmd.py
new file mode 100644
index 0000000..8bb9362
--- /dev/null
+++ b/tests/test_address_cmd.py
@@ -0,0 +1,64 @@
+import pytest
+
+from ragger.bip import calculate_public_key_and_chaincode, CurveChoice
+from ragger.error import ExceptionRAPDU
+from ragger.backend.interface import BackendInterface
+from ragger.navigator.navigation_scenario import NavigateWithScenario
+
+from application_client.everscale_command_sender import EverscaleCommandSender, Errors, WalletType
+from application_client.everscale_response_unpacker import unpack_get_address_response
+
+HARDENED_OFFSET = 0x80000000
+PATH_PREFIX = "44'/396'/"
+PATH_SUFFIX = "'/0'/0'"
+ # 9 types of wallets
+EXPECTED_ADDRESSES = [
+ '7571b498e3fed7a0fffbe21377e50548c92da4a04842e1b163547d3e8980cf64', '522a4cc774797f537c41b4853a9b83f359fe2802a5cf3bd9f31240c495e82358', 'ae990783e06a196ab03029fe4517dda0ea318c091cd49ff51cc0a40369b0aff5', '98135fb68e91833e810122abfe00ff3b38c1d555bf773741f869dea8b87fb72d', '23e76dee54e3f715e11cf374177e786878814ad2c7ac6e38bc06515efdb5fab3', '0806dbe6c4581af1165879fd196d3e02404029540e818921edfedbffb46d3c65', 'ec03eb7af13d70083b9f3c8202b0321ede255edc624292c531106f50d9f005b3', '9760a1b7393cdbb389205f72ebf4d7e362b06b419fdac9aeccd83bf39ce0d05a', '1de569744cf341d8e2e35996f23cdf5d5f9226c1400c98100f480d89e70c6bcf'
+]
+
+# In this test we check that the GET_ADDRESS works in non-confirmation mode
+@pytest.mark.active_test_scope
+def test_get_address_all_types_no_confirm(backend: BackendInterface) -> None:
+ temp = []
+ for wallet_type in range(9):
+ client = EverscaleCommandSender(backend)
+ response = client.get_address(account_number=0, wallet_type=wallet_type).data
+ _, address = unpack_get_address_response(response)
+
+ assert address.hex() == EXPECTED_ADDRESSES[wallet_type], f"Error with wallet_type: {wallet_type}, expected: {EXPECTED_ADDRESSES[wallet_type]}, but got {address.hex()}"
+
+
+# In this test we check that the GET_ADDRESS works in confirmation mode
+@pytest.mark.active_test_scope
+def test_get_address_wallet_v3_confirm_accepted(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None:
+ client = EverscaleCommandSender(backend)
+ account_number = 0
+ wallet_type = WalletType.WALLET_V3
+ with client.get_address_with_confirmation(account_number=account_number, wallet_type=wallet_type):
+ scenario_navigator.address_review_approve()
+
+ response = client.get_async_response().data
+ _, address = unpack_get_address_response(response)
+
+ assert address.hex() == EXPECTED_ADDRESSES[wallet_type], f"Error with wallet_type: {wallet_type}, expected: {EXPECTED_ADDRESSES[wallet_type]}, but got {address.hex()}"
+
+
+# In this test we check that the GET_ADDRESS in confirmation mode replies an error if the user refuses
+@pytest.mark.active_test_scope
+def test_get_address_wallet_v3_confirm_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None:
+ client = EverscaleCommandSender(backend)
+ account_number = 0
+ wallet_type = WalletType.WALLET_V3
+
+ with pytest.raises(ExceptionRAPDU) as e:
+ with client.get_address_with_confirmation(account_number=account_number, wallet_type=wallet_type):
+ scenario_navigator.address_review_reject()
+
+ # Assert that we have received a refusal
+ assert e.value.status == Errors.SW_DENY
+ assert len(e.value.data) == 0
+
+
+
+
+
diff --git a/tests/test_app_config_cmd.py b/tests/test_app_config_cmd.py
new file mode 100644
index 0000000..b272b86
--- /dev/null
+++ b/tests/test_app_config_cmd.py
@@ -0,0 +1,18 @@
+import pytest
+from ragger.backend.interface import BackendInterface
+
+from application_client.everscale_command_sender import EverscaleCommandSender
+from application_client.everscale_response_unpacker import unpack_get_version_response
+
+from utils import verify_version
+
+# In this test we check the behavior of the device when asked to provide the app version
+@pytest.mark.active_test_scope
+def test_get_app_config(backend: BackendInterface) -> None:
+ # Use the app interface instead of raw interface
+ client = EverscaleCommandSender(backend)
+ # Send the GET_VERSION instruction
+ rapdu = client.get_app_config()
+ # Use an helper to parse the response, assert the values
+ MAJOR, MINOR, PATCH = unpack_get_version_response(rapdu.data)
+ verify_version(f"{MAJOR}.{MINOR}.{PATCH}")
diff --git a/tests/test_pubkey_cmd.py b/tests/test_pubkey_cmd.py
new file mode 100644
index 0000000..4082abe
--- /dev/null
+++ b/tests/test_pubkey_cmd.py
@@ -0,0 +1,69 @@
+import pytest
+
+from ragger.bip import calculate_public_key_and_chaincode, CurveChoice
+from ragger.error import ExceptionRAPDU
+from ragger.backend.interface import BackendInterface
+from ragger.navigator import NavInsID
+from ragger.navigator.navigation_scenario import NavigateWithScenario
+
+from utils import navigate_until_text_and_compare
+
+from application_client.everscale_command_sender import EverscaleCommandSender, Errors
+from application_client.everscale_response_unpacker import unpack_get_public_key_response
+
+HARDENED_OFFSET = 0x80000000
+PATH_PREFIX = "44'/396'/"
+PATH_SUFFIX = "'/0'/0'"
+
+# In this test we check that the GET_PUBLIC_KEY works in non-confirmation mode
+@pytest.mark.active_test_scope
+def test_get_public_key_no_confirm(backend: BackendInterface) -> None:
+ account_number_list = [
+ 0,
+ 1,
+ 911,
+ 255,
+ 2147483647
+ ]
+ for account_number in account_number_list:
+ client = EverscaleCommandSender(backend)
+ response = client.get_public_key(account_number=account_number).data
+ _, public_key = unpack_get_public_key_response(response)
+
+ ref_public_key, _ = calculate_public_key_and_chaincode(CurveChoice.Ed25519Slip, path=PATH_PREFIX + str(account_number | HARDENED_OFFSET) + PATH_SUFFIX)
+ assert "00" + public_key.hex() == ref_public_key
+
+
+# In this test we check that the GET_PUBLIC_KEY works in confirmation mode
+@pytest.mark.active_test_scope
+def test_get_public_key_confirm_accepted(backend: BackendInterface, firmware, navigator, default_screenshot_path, test_name) -> None:
+ client = EverscaleCommandSender(backend)
+ account_number = 0
+ with client.get_public_key_with_confirmation(account_number=account_number):
+ navigate_until_text_and_compare(firmware, navigator, "Approve", default_screenshot_path, test_name, True, True, [NavInsID.USE_CASE_CHOICE_CONFIRM])
+
+ response = client.get_async_response().data
+ _, public_key = unpack_get_public_key_response(response)
+
+ ref_public_key, _ = calculate_public_key_and_chaincode(CurveChoice.Ed25519Slip, path=PATH_PREFIX + str(account_number | HARDENED_OFFSET) + PATH_SUFFIX)
+ assert "00" + public_key.hex() == ref_public_key
+
+
+# In this test we check that the GET_PUBLIC_KEY in confirmation mode replies an error if the user refuses
+@pytest.mark.active_test_scope
+def test_get_public_key_confirm_refused(backend: BackendInterface, firmware, navigator, default_screenshot_path, test_name, scenario_navigator) -> None:
+ client = EverscaleCommandSender(backend)
+ account_number = 0
+
+ confirm_instructions = [NavInsID.USE_CASE_CHOICE_REJECT, NavInsID.USE_CASE_CHOICE_CONFIRM]
+
+ with pytest.raises(ExceptionRAPDU) as e:
+ with client.get_public_key_with_confirmation(account_number=account_number):
+ navigate_until_text_and_compare(firmware, navigator, "Reject", default_screenshot_path, test_name, True, True, confirm_instructions)
+
+ # with client.get_public_key_with_confirmation(account_number=account_number):
+ # scenario_navigator.address_review_reject()
+
+ # Assert that we have received a refusal
+ assert e.value.status == Errors.SW_DENY
+ assert len(e.value.data) == 0
diff --git a/tests/test_sign_cmd.py b/tests/test_sign_cmd.py
new file mode 100644
index 0000000..faf8e57
--- /dev/null
+++ b/tests/test_sign_cmd.py
@@ -0,0 +1,220 @@
+import pytest
+
+from ragger.backend.interface import BackendInterface
+from ragger.error import ExceptionRAPDU
+from ragger.firmware import Firmware
+from ragger.navigator import Navigator, NavInsID
+from ragger.navigator.navigation_scenario import NavigateWithScenario
+
+from application_client.everscale_command_sender import EverscaleCommandSender
+from application_client.everscale_response_unpacker import unpack_sign_tx_response
+from utils import navigate_until_text_and_compare
+
+
+def run_test(
+ backend: BackendInterface,
+ navigator: Navigator,
+ default_screenshot_path: str,
+ test_name: str,
+ transaction: str,
+ expected_signature: str,
+ scenario_navigator: NavigateWithScenario,
+ firmware,
+) -> None:
+ # Use the app interface instead of raw interface
+ client = EverscaleCommandSender(backend)
+
+ # Raw transaction
+ transaction_bytes = bytes.fromhex(transaction)
+
+ # Send the sign device instruction.
+ # As it requires on-screen validation, the function is asynchronous.
+ # It will yield the result when the navigation is done
+ with client.sign_tx(transaction_bytes):
+ # Validate the on-screen request by performing the navigation appropriate for this device
+ if firmware.is_nano:
+ navigate_until_text_and_compare(
+ backend.firmware,
+ navigator,
+ "Approve",
+ default_screenshot_path,
+ test_name,
+ )
+ else:
+ scenario_navigator.review_approve()
+
+ # The device as yielded the result, parse it and ensure that the signature is correct
+ response = client.get_async_response().data
+ _, der_sig, _ = unpack_sign_tx_response(response)
+ assert der_sig.hex() == expected_signature
+
+
+# In this tests we check the behavior of the device when asked to sign a transaction
+
+
+# In this test we send to the device a transaction to sign and validate it on screen
+# The transaction is short and will be sent in one chunk
+# We will ensure that the displayed information is correct by using screenshots comparison
+
+
+@pytest.mark.active_test_scope
+def test_sign_tx_burn_usdt(
+ backend: BackendInterface,
+ navigator: Navigator,
+ default_screenshot_path: str,
+ test_name: str,
+ scenario_navigator,
+ firmware,
+) -> None:
+ run_test(
+ backend,
+ navigator,
+ default_screenshot_path,
+ test_name,
+ "0000000001090455534454000101040100c9002161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e2c951fb3d692b2a677323640012165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d03802216b562548ad00000000000000000000000049504f808015e4256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ad00328480101c03bf4894e22cdd500e450cbe5838b9938fda1e4d3727fe3b5385c5114b0293f0001", # Transaction
+ "a8b3ee327f6a64945e875d59ec49b12bea553b30170be65c541176f052156035428f8a0180e9f8802622b4f3339f2161076790b822e55c0d46f01b919f6de005", # Expected_signature
+ scenario_navigator,
+ firmware,
+ )
+
+
+@pytest.mark.active_test_scope
+def test_sign_tx_confirm(
+ backend: BackendInterface,
+ navigator: Navigator,
+ default_screenshot_path: str,
+ test_name: str,
+ scenario_navigator,
+ firmware,
+) -> None:
+ run_test(
+ backend,
+ navigator,
+ default_screenshot_path,
+ test_name,
+ "00000000020904455645520001010101003b000071b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7e395aa2b3d695f78d53a076b24a0de621e6767fc0", # Transaction
+ "8a5a9435d8b85f37f0d0b6dd0cb39521c8acf3f04cff7d53a4fb83e05313baace8b63b0fc3d8e6d0f9dd1922bc65df11efbecb9c34e4c79ec2a7267d67613e0e", # Expected_signature
+ scenario_navigator,
+ firmware,
+ )
+
+
+# TODO: Add tests for the other transaction types
+
+
+@pytest.mark.active_test_scope
+def test_sign_tx_transfer(
+ backend: BackendInterface,
+ navigator: Navigator,
+ default_screenshot_path: str,
+ test_name: str,
+ scenario_navigator,
+ firmware,
+) -> None:
+ run_test(
+ backend,
+ navigator,
+ default_screenshot_path,
+ test_name,
+ "00000000010904455645520001010301006c000161b3badb535d1b88d0e4d60d316567b1448568efafdf21846ecd0ba02e3adabf97000000ca7cfb9642b3d6449ea677323640010165801be2256b3d704f24c46aea3298c1a5ea8f8d1aa86ccc89474bc0570265e7898ac0000000000000000036d36956f8b969d038020000", # Transaction
+ "a0396cd952160f068e0a7d6279ba2b61a2215a4dd997fcc1fe8905722341a20a86424dfdb2598b86855e73e47a1804023ff3f9afffd91825df0f58825dabd808", # Expected_signature
+ scenario_navigator,
+ firmware,
+ )
+
+
+# # In this test we send to the device a transaction to trig a blind-signing flow
+# # The transaction is short and will be sent in one chunk
+# # We will ensure that the displayed information is correct by using screenshots comparison
+# def test_sign_tx_short_tx_blind_sign(firmware: Firmware,
+# backend: BackendInterface,
+# navigator: Navigator,
+# scenario_navigator: NavigateWithScenario,
+# test_name: str,
+# default_screenshot_path: str) -> None:
+# # Use the app interface instead of raw interface
+# client = EverscaleCommandSender(backend)
+# # The path used for this entire test
+# path: str = "m/44'/1'/0'/0/0"
+
+# # First we need to get the public key of the device in order to build the transaction
+# rapdu = client.get_public_key(path=path)
+# _, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
+
+# # Create the transaction that will be sent to the device for signing
+# transaction = Transaction(
+# nonce=1,
+# to="0x0000000000000000000000000000000000000000",
+# value=0,
+# memo="Blind-sign"
+# ).serialize()
+
+# # Send the sign device instruction.
+# valid_instruction = [NavInsID.RIGHT_CLICK] if firmware.is_nano else [NavInsID.USE_CASE_CHOICE_REJECT]
+# # As it requires on-screen validation, the function is asynchronous.
+# # It will yield the result when the navigation is done
+# with client.sign_tx(path=path, transaction=transaction):
+# navigator.navigate_and_compare(default_screenshot_path,
+# test_name+"/part1",
+# valid_instruction,
+# screen_change_after_last_instruction=False)
+
+# # Validate the on-screen request by performing the navigation appropriate for this device
+# scenario_navigator.review_approve()
+
+# # The device as yielded the result, parse it and ensure that the signature is correct
+# response = client.get_async_response().data
+# _, der_sig, _ = unpack_sign_tx_response(response)
+# assert check_signature_validity(public_key, der_sig, transaction)
+
+# # In this test se send to the device a transaction to sign and validate it on screen
+# # This test is mostly the same as the previous one but with different values.
+# # In particular the long memo will force the transaction to be sent in multiple chunks
+# def test_sign_tx_long_tx(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None:
+# # Use the app interface instead of raw interface
+# client = EverscaleCommandSender(backend)
+# path: str = "m/44'/1'/0'/0/0"
+
+# rapdu = client.get_public_key(path=path)
+# _, public_key, _, _ = unpack_get_public_key_response(rapdu.data)
+
+# transaction = Transaction(
+# nonce=1,
+# to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
+# value=666,
+# memo=("This is a very long memo. "
+# "It will force the app client to send the serialized transaction to be sent in chunk. "
+# "As the maximum chunk size is 255 bytes we will make this memo greater than 255 characters. "
+# "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed non risus. Suspendisse lectus tortor, "
+# "dignissim sit amet, adipiscing nec, ultricies sed, dolor. Cras elementum ultrices diam.")
+# ).serialize()
+
+# with client.sign_tx(path=path, transaction=transaction):
+# scenario_navigator.review_approve()
+
+# response = client.get_async_response().data
+# _, der_sig, _ = unpack_sign_tx_response(response)
+# assert check_signature_validity(public_key, der_sig, transaction)
+
+
+# # Transaction signature refused test
+# # The test will ask for a transaction signature that will be refused on screen
+# def test_sign_tx_refused(backend: BackendInterface, scenario_navigator: NavigateWithScenario) -> None:
+# # Use the app interface instead of raw interface
+# client = EverscaleCommandSender(backend)
+# path: str = "m/44'/1'/0'/0/0"
+
+# transaction = Transaction(
+# nonce=1,
+# to="0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
+# value=666,
+# memo="This transaction will be refused by the user"
+# ).serialize()
+
+# with pytest.raises(ExceptionRAPDU) as e:
+# with client.sign_tx(path=path, transaction=transaction):
+# scenario_navigator.review_reject()
+
+# # Assert that we have received a refusal
+# assert e.value.status == Errors.SW_DENY
+# assert len(e.value.data) == 0
diff --git a/tests/test_sign_message_cmd.py b/tests/test_sign_message_cmd.py
new file mode 100644
index 0000000..f92914f
--- /dev/null
+++ b/tests/test_sign_message_cmd.py
@@ -0,0 +1,53 @@
+import pytest
+
+from ragger.backend.interface import BackendInterface
+from ragger.error import ExceptionRAPDU
+from ragger.firmware import Firmware
+from ragger.navigator import Navigator, NavInsID
+from ragger.navigator.navigation_scenario import NavigateWithScenario
+
+from application_client.everscale_command_sender import EverscaleCommandSender, Errors, WalletType
+from application_client.everscale_response_unpacker import unpack_get_public_key_response, unpack_sign_tx_response
+from utils import navigate_until_text_and_compare
+
+# In this tests we check the behavior of the device when asked to sign a transaction
+
+
+# In this test we send to the device a transaction to sign and validate it on screen
+# The transaction is short and will be sent in one chunk
+# We will ensure that the displayed information is correct by using screenshots comparison
+
+# TODO: Add a valid raw message and a valid expected signature
+@pytest.mark.active_test_scope
+def test_sign_message(backend: BackendInterface, navigator: Navigator, default_screenshot_path: str, test_name: str, scenario_navigator, firmware) -> None:
+ # Use the app interface instead of raw interface
+ client = EverscaleCommandSender(backend)
+ account_number = 0
+ wallet_type = WalletType.WALLET_V3
+ # First we need to get the public key of the device in order to build the transaction
+ rapdu = client.get_public_key(account_number=account_number)
+
+ # Message to sign
+ message_hash = "1111111111111111111111111111111111111111111111111111111111111111"
+ message_bytes = bytes.fromhex(message_hash)
+ payload = account_number.to_bytes(4, byteorder='big') + message_bytes
+ # Send the sign device instruction.
+ # As it requires on-screen validation, the function is asynchronous.
+ # It will yield the result when the navigation is done
+ with client.sign_message(payload=payload):
+ # Validate the on-screen request by performing the navigation appropriate for this device
+ if firmware.is_nano:
+ navigate_until_text_and_compare(
+ backend.firmware,
+ navigator,
+ "message.",
+ default_screenshot_path,
+ test_name
+ )
+ else:
+ scenario_navigator.review_approve()
+
+ # The device as yielded the result, parse it and ensure that the signature is correct
+ response = client.get_async_response().data
+ _, der_sig, _ = unpack_sign_tx_response(response)
+ assert der_sig.hex() == "d4883fb9095f3610dfc0888917c8b5548c7074f0f010966c94a5c405ccabe8d320c90334786dbf2b34f10e75c5370ae151b0b11cb190a16d7509983964d6dd00"
\ No newline at end of file
diff --git a/tests/usage.md b/tests/usage.md
new file mode 100644
index 0000000..dc2fbfa
--- /dev/null
+++ b/tests/usage.md
@@ -0,0 +1,78 @@
+# How to use the Ragger test framework
+
+This framework allows testing the application on the Speculos emulator or on a real device using LedgerComm or LedgerWallet
+
+## Quickly get started with Ragger and Speculos
+
+### Install ragger and dependencies
+
+```shell
+pip install --extra-index-url https://test.pypi.org/simple/ -r requirements.txt
+sudo apt-get update && sudo apt-get install qemu-user-static
+```
+
+### Compile the application
+
+The application to test must be compiled for all required devices.
+You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`:
+
+```shell
+docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest
+cd # replace with the name of your app, (eg boilerplate)
+docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest
+make clean && make BOLOS_SDK=$_SDK # replace with one of [NANOX, NANOSP, STAX, FLEX]
+exit
+```
+
+### Run a simple test using the Speculos emulator
+
+You can use the following command to get your first experience with Ragger and Speculos
+
+```shell
+pytest -v --tb=short --device nanox --display
+```
+
+Or you can refer to the section `Available pytest options` to configure the options you want to use
+
+### Run a simple test using a real device
+
+The application to test must be loaded and started on a Ledger device plugged in USB.
+You can use for this the container `ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite`:
+
+```shell
+docker pull ghcr.io/ledgerhq/ledger-app-builder/ledger-app-builder-lite:latest
+cd app-/ # replace with the name of your app, (eg boilerplate)
+docker run --user "$(id -u)":"$(id -g)" --rm -ti -v "$(realpath .):/app" --privileged -v "/dev/bus/usb:/dev/bus/usb" ledger-app-builder-lite:latest
+make clean && make BOLOS_SDK=$_SDK load # replace with one of [NANOX, NANOSP, STAX, FLEX]
+exit
+```
+
+You can use the following command to get your first experience with Ragger and Ledgerwallet on a NANOX.
+Make sure that the device is plugged, unlocked, and that the tested application is open.
+
+```shell
+pytest -v --tb=short --device nanox --backend ledgerwallet
+```
+
+Or you can refer to the section `Available pytest options` to configure the options you want to use
+
+## Available pytest options
+
+Standard useful pytest options
+
+```shell
+ -v formats the test summary in a readable way
+ -s enable logs for successful tests, on Speculos it will enable app logs if compiled with DEBUG=1
+ -k only run the tests that contain in their names
+ --tb=short in case of errors, formats the test traceback in a readable way
+```
+
+Custom pytest options
+
+```shell
+ --device run the test on the specified device [nanox,nanosp,stax,flex,all]. This parameter is mandatory
+ --backend run the tests against the backend [speculos, ledgercomm, ledgerwallet]. Speculos is the default
+ --display on Speculos, enables the display of the app screen using QT
+ --golden_run on Speculos, screen comparison functions will save the current screen instead of comparing
+ --log_apdu_file log all apdu exchanges to the file in parameter. The previous file content is erased
+```
diff --git a/tests/utils.py b/tests/utils.py
new file mode 100644
index 0000000..c8bdc35
--- /dev/null
+++ b/tests/utils.py
@@ -0,0 +1,129 @@
+from pathlib import Path
+from typing import List
+import re
+from Crypto.Hash import keccak
+
+from ecdsa.curves import SECP256k1
+from ecdsa.keys import VerifyingKey
+from ecdsa.util import sigdecode_der
+from ragger.navigator import NavInsID
+
+# Check if a signature of a given message is valid
+def check_signature_validity(public_key: bytes, signature: bytes, message: bytes) -> bool:
+ pk: VerifyingKey = VerifyingKey.from_string(
+ public_key,
+ curve=SECP256k1,
+ hashfunc=None
+ )
+ # Compute message hash (keccak_256)
+ k = keccak.new(digest_bits=256)
+ k.update(message)
+ message_hash = k.digest()
+
+ return pk.verify_digest(signature=signature,
+ digest=message_hash,
+ sigdecode=sigdecode_der)
+
+
+def verify_name(name: str) -> None:
+ """Verify the app name, based on defines in Makefile
+
+ Args:
+ name (str): Name to be checked
+ """
+
+ name_str = ""
+ lines = _read_makefile()
+ name_re = re.compile(r"^APPNAME\s?=\s?\"?(?P\w+)\"?", re.I)
+ for line in lines:
+ info = name_re.match(line)
+ if info:
+ dinfo = info.groupdict()
+ name_str = dinfo["val"]
+ assert name == name_str
+
+
+def verify_version(version: str) -> None:
+ """Verify the app version, based on defines in Makefile
+
+ Args:
+ Version (str): Version to be checked
+ """
+
+ vers_dict = {}
+ vers_str = ""
+ lines = _read_makefile()
+ version_re = re.compile(r"^APPVERSION_(?P\w)\s?=\s?(?P\d*)", re.I)
+ for line in lines:
+ info = version_re.match(line)
+ if info:
+ dinfo = info.groupdict()
+ vers_dict[dinfo["part"]] = dinfo["val"]
+ try:
+ vers_str = f"{vers_dict['M']}.{vers_dict['N']}.{vers_dict['P']}"
+ except KeyError:
+ pass
+ assert version == vers_str
+
+
+def _read_makefile() -> List[str]:
+ """Read lines from the parent Makefile """
+
+ parent = Path(__file__).parent.parent.resolve()
+ makefile = f"{parent}/Makefile"
+ with open(makefile, "r", encoding="utf-8") as f_p:
+ lines = f_p.readlines()
+ return lines
+
+
+def navigate_until_text_and_compare(
+ firmware,
+ navigator,
+ text: str,
+ screenshot_path: str,
+ test_name: str,
+ screen_change_before_first_instruction: bool = True,
+ screen_change_after_last_instruction: bool = True,
+ nav_ins_confirm_instruction: List[NavInsID] = [NavInsID.USE_CASE_REVIEW_CONFIRM],
+):
+ """Navigate through device screens until specified text is found and compare screenshots.
+
+ This function handles navigation through device screens differently based on the device type (Stax/Flex vs others).
+ It will navigate through screens until the specified text is found, taking screenshots for comparison along the way.
+
+ Args:
+ firmware: The firmware object containing device information
+ navigator: The navigator object used to control device navigation
+ text: The text string to search for on device screens
+ screenshot_path: Path where screenshot comparison files will be saved
+ test_name: The name of the test that is being run
+ screen_change_before_first_instruction: Whether to wait for screen change before first instruction
+ screen_change_after_last_instruction: Whether to wait for screen change after last instruction
+ Returns:
+ None
+
+ Note:
+ For Stax/Flex devices:
+ - Uses swipe left gesture for navigation
+ - Uses review confirm for confirmation
+ For other devices:
+ - Uses right click for navigation
+ - Uses both click for confirmation
+ """
+ if firmware.device.startswith(("stax", "flex")):
+ go_right_instruction = NavInsID.SWIPE_CENTER_TO_LEFT
+ confirm_instructions = nav_ins_confirm_instruction
+ else:
+ go_right_instruction = NavInsID.RIGHT_CLICK
+ confirm_instructions = [NavInsID.BOTH_CLICK]
+
+ navigator.navigate_until_text_and_compare(
+ go_right_instruction,
+ confirm_instructions,
+ text,
+ screenshot_path,
+ test_name,
+ 300,
+ screen_change_before_first_instruction,
+ screen_change_after_last_instruction,
+ )