diff --git a/.github/actions/ui-comment/action.yml b/.github/actions/ui-comment/action.yml index 7ae49e7197..e72e7b4d7c 100644 --- a/.github/actions/ui-comment/action.yml +++ b/.github/actions/ui-comment/action.yml @@ -4,7 +4,7 @@ runs: using: composite steps: - name: Find Comment - uses: peter-evans/find-comment@v2 + uses: peter-evans/find-comment@v3 id: fc if: github.event_name == 'pull_request' with: @@ -13,7 +13,7 @@ runs: body-includes: ui-comment-${{ github.workflow }} - name: Create or update comment - uses: peter-evans/create-or-update-comment@v3 + uses: peter-evans/create-or-update-comment@v4 if: github.event_name == 'pull_request' with: comment-id: ${{ steps.fc.outputs.comment-id }} diff --git a/.github/actions/ui-report/action.yml b/.github/actions/ui-report/action.yml index f8d360e337..170e902602 100644 --- a/.github/actions/ui-report/action.yml +++ b/.github/actions/ui-report/action.yml @@ -38,12 +38,12 @@ runs: shell: sh - name: Upload report run: | - aws s3 sync ${{ github.run_id }} s3://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }} + aws s3 sync --no-progress ${{ github.run_id }} s3://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }} echo "[UI test report](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/${{ inputs.model }}-${{ inputs.lang }}-${{ github.job }}/index.html)" >> $GITHUB_STEP_SUMMARY shell: sh - name: Upload test screen recording run: | - aws s3 sync ci/ui_test_records s3://data.trezor.io/dev/firmware/ui_tests + aws s3 sync --no-progress ci/ui_test_records s3://data.trezor.io/dev/firmware/ui_tests # TODO: generate directory listing / autoindex shell: sh - uses: actions/upload-artifact@v4 diff --git a/.github/workflows/bot-common-sync.yml b/.github/workflows/bot-common-sync.yml new file mode 100644 index 0000000000..f6686a0e38 --- /dev/null +++ b/.github/workflows/bot-common-sync.yml @@ -0,0 +1,43 @@ +name: "[Bot] sync to trezor-common repository" + +on: + schedule: + - cron: "0 0 * * *" + workflow_dispatch: + +permissions: + contents: read + +jobs: + sync-common: + runs-on: ubuntu-latest + env: + BOT_TOKEN: ${{ secrets.BOT_TOKEN_COMMON_FINE }} + BOT_USERNAME: ${{ secrets.TREZOR_BOT_USERNAME }} + BOT_EMAIL: ${{ secrets.TREZOR_BOT_EMAIL }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Copy git-filter and script to temporary directory + run: | + cp ./ci/common_sync/common_repo_sync.sh ${{runner.temp}}/common_repo_sync.sh + cp ./ci/common_sync/git-filter-repo ${{runner.temp}}/git-filter-repo + + - name: Confiugre git user + run: | + git config --global user.name "${BOT_USERNAME}" + git config --global user.email "${BOT_EMAIL}" + + - name: Add git-filter-repo to PATH + run: | + echo "Adding git-filter-repo to PATH" + echo '${{runner.temp}}' >> $GITHUB_PATH + + - name: Sync trezor-common repository + run: | + echo "Synchronizing common with the trezor-common repository" + git config --unset-all http.https://github.com/.extraheader + ${{ runner.temp }}/common_repo_sync.sh diff --git a/.github/workflows/common.yml b/.github/workflows/common.yml index 44a95bcfdf..60ec8231fa 100644 --- a/.github/workflows/common.yml +++ b/.github/workflows/common.yml @@ -1,6 +1,10 @@ name: Common -on: [pull_request] +on: + pull_request: + workflow_dispatch: + schedule: + - cron: '14 23 * * *' # every day @ 23:14 jobs: crypto_build: diff --git a/.github/workflows/core.yml b/.github/workflows/core.yml index 3e36703565..d5b16c5b07 100644 --- a/.github/workflows/core.yml +++ b/.github/workflows/core.yml @@ -21,7 +21,7 @@ env: |core UI changes|device test|click test|persistence test| |---------------|-----------|----------|----------------| |T2T1 Model T | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_device_test/master_diff.html)) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_click_test/master_diff.html)) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2T1-en-core_persistence_test/master_diff.html))|| - |T2B1 Safe 3 |[3280](https://github.com/trezor/trezor-firmware/issues/3280) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-en-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-en-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-en-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T2B1-en-core_click_test/master_diff.html)) |[2724](https://github.com/trezor/trezor-firmware/issues/2724) || + |T3B1 Safe 3 | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_device_test/master_diff.html)) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3B1-en-core_click_test/master_diff.html)) |[2724](https://github.com/trezor/trezor-firmware/issues/2724) || |T3T1 | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_device_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_device_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_device_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_device_test/master_diff.html)) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_click_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_click_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_click_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_click_test/master_diff.html)) | [test](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_persistence_test/index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_persistence_test/differing_screens.html)) [main](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_persistence_test/master_index.html)([screens](https://data.trezor.io/dev/firmware/ui_report/${{ github.run_id }}/T3T1-en-core_persistence_test/master_diff.html))|| |All | [main](https://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }}/index.html)([screens](https://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }}/master_diff.html)) || @@ -36,7 +36,7 @@ jobs: - id: set_vars name: Set variables run: | - echo test_lang=${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'translations') && '[\"en\", \"cs\", \"fr\", \"de\", \"es\"]' || '[\"en\"]' }} >> $GITHUB_OUTPUT + echo test_lang=${{ github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'translations') && '[\"en\", \"cs\", \"fr\", \"de\", \"es\", \"it\", \"pt\"]' || '[\"en\"]' }} >> $GITHUB_OUTPUT echo asan=${{ github.event_name == 'schedule' && '[\"noasan\", \"asan\"]' || '[\"noasan\"]' }} >> $GITHUB_OUTPUT cat $GITHUB_OUTPUT @@ -46,7 +46,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] coins: [universal, btconly] type: ${{ fromJSON(github.event_name == 'schedule' && '["normal", "debuglink", "production"]' || '["normal", "debuglink"]') }} include: @@ -54,11 +54,10 @@ jobs: coins: universal type: normal env: - TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'T2B1' && 'R' || matrix.model == 'D001' && 'DISC1' || matrix.model }} + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'D001' && 'DISC1' || matrix.model }} BITCOIN_ONLY: ${{ matrix.coins == 'universal' && '0' || '1' }} PYOPT: ${{ matrix.type == 'debuglink' && '0' || '1' }} PRODUCTION: ${{ matrix.type == 'production' && '1' || '0' }} - BOOTLOADER_DEVEL: ${{ matrix.model == 'T3T1' && '1' || '0' }} steps: - uses: actions/checkout@v4 with: @@ -96,7 +95,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] coins: [universal, btconly] # type: [normal, debuglink] type: [debuglink] @@ -105,12 +104,10 @@ jobs: - type: normal asan: asan env: - TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'T2B1' && 'R' || matrix.model }} + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model }} BITCOIN_ONLY: ${{ matrix.coins == 'universal' && '0' || '1' }} PYOPT: ${{ matrix.type == 'debuglink' && '0' || '1' }} ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} - RUSTC_BOOTSTRAP: ${{ matrix.asan == 'asan' && '1' || '0' }} - RUSTFLAGS: ${{ matrix.asan == 'asan' && '-Z sanitizer=address' || '' }} LSAN_OPTIONS: "suppressions=../../asan_suppressions.txt" steps: - uses: actions/checkout@v4 @@ -129,6 +126,44 @@ jobs: core/build/bootloader_emu/bootloader.elf retention-days: 7 + core_emu_arm: + if: github.event_name == 'schedule' + name: Build emu arm + runs-on: ubuntu-latest-arm64 + needs: param + strategy: + fail-fast: false + matrix: + model: [T2T1, T3B1, T3T1] + coins: [universal] + type: [debuglink] + asan: [noasan] + exclude: + - type: normal + asan: asan + env: + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model }} + BITCOIN_ONLY: ${{ matrix.coins == 'universal' && '0' || '1' }} + PYOPT: ${{ matrix.type == 'debuglink' && '0' || '1' }} + ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} + LSAN_OPTIONS: "suppressions=../../asan_suppressions.txt" + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: ./.github/actions/environment + - run: nix-shell --run "poetry run make -C core build_bootloader_emu" + if: matrix.coins == 'universal' + - run: nix-shell --run "poetry run make -C core build_unix_frozen" + - run: mv core/build/unix/trezor-emu-core core/build/unix/trezor-emu-arm-core-${{ matrix.model }}-${{ matrix.coins }} + - uses: actions/upload-artifact@v4 + with: + name: core-emu-arm-${{ matrix.model }}-${{ matrix.coins }}-${{ matrix.type }}-${{ matrix.asan }} + path: | + core/build/unix/trezor-emu-* + core/build/bootloader_emu/bootloader.elf + retention-days: 2 + core_unit_python_test: name: Python unit tests runs-on: ubuntu-latest @@ -136,10 +171,10 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} env: - TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'T2B1' && 'R' || matrix.model }} + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model }} ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} LSAN_OPTIONS: "suppressions=../../asan_suppressions.txt" steps: @@ -159,10 +194,10 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1] + model: [T2T1, T3B1, T3T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} env: - TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'T2B1' && 'R' || matrix.model }} + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model }} ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} RUSTC_BOOTSTRAP: ${{ matrix.asan == 'asan' && '1' || '0' }} RUSTFLAGS: ${{ matrix.asan == 'asan' && '-Z sanitizer=address' || '' }} @@ -183,7 +218,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1] + model: [T2T1, T3B1] steps: - uses: actions/checkout@v4 with: @@ -209,17 +244,13 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] coins: [universal, btconly] asan: ${{ fromJSON(needs.param.outputs.asan) }} lang: ${{ fromJSON(needs.param.outputs.test_lang) }} - # T2B1 fails due to https://github.com/trezor/trezor-firmware/issues/3280 - # remove after single global layout is implemented (or bug above fixed): - exclude: - - model: T2B1 env: TREZOR_PROFILING: ${{ matrix.asan == 'noasan' && '1' || '0' }} - TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model == 'T2B1' && 'R' || matrix.model }} + TREZOR_MODEL: ${{ matrix.model == 'T2T1' && 'T' || matrix.model }} TREZOR_PYTEST_SKIP_ALTCOINS: ${{ matrix.coins == 'btconly' && '1' || '0' }} ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} PYTEST_TIMEOUT: ${{ matrix.asan == 'asan' && 600 || 400 }} @@ -268,10 +299,11 @@ jobs: needs: - param - core_emu + timeout-minutes: 90 strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} lang: ${{ fromJSON(needs.param.outputs.test_lang) }} env: @@ -324,7 +356,7 @@ jobs: strategy: fail-fast: false matrix: - # FIXME: T2B1 https://github.com/trezor/trezor-firmware/issues/2724 + # FIXME: T3B1 https://github.com/trezor/trezor-firmware/issues/2724 # FIXME: T3T1 https://github.com/trezor/trezor-firmware/issues/3595 model: [T2T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} @@ -352,10 +384,11 @@ jobs: needs: - param - core_emu + timeout-minutes: 30 strategy: fail-fast: false matrix: - model: [T2T1, T3T1] # TODO T2B1 https://github.com/trezor/trezor-firmware/issues/2724 + model: [T2T1, T3T1] # TODO T3B1 https://github.com/trezor/trezor-firmware/issues/2724 asan: ${{ fromJSON(needs.param.outputs.asan) }} env: TREZOR_PROFILING: ${{ matrix.asan == 'noasan' && '1' || '0' }} @@ -397,7 +430,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] steps: - uses: actions/checkout@v4 with: @@ -455,7 +488,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1] # FIXME: checker.py lacks awareness of T3T1 flash layout + model: [T2T1] # FIXME: checker.py lacks awareness of U5 flash layout steps: - uses: actions/checkout@v4 with: @@ -506,7 +539,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} env: TREZOR_PROFILING: ${{ matrix.asan == 'noasan' && '1' || '0' }} @@ -551,7 +584,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] + model: [T2T1, T3B1, T3T1] asan: ${{ fromJSON(needs.param.outputs.asan) }} env: TREZOR_PROFILING: ${{ matrix.asan == 'noasan' && '1' || '0' }} @@ -591,7 +624,7 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T3T1] # XXX T2B1 https://github.com/trezor/trezor-firmware/issues/2724 + model: [T2T1, T3T1] # XXX T3B1 https://github.com/trezor/trezor-firmware/issues/2724 asan: ${{ fromJSON(needs.param.outputs.asan) }} env: TREZOR_PROFILING: ${{ matrix.asan == 'noasan' && '1' || '0' }} @@ -634,11 +667,11 @@ jobs: strategy: fail-fast: false matrix: - model: [T2T1, T2B1, T3T1] - # T2B1 fails due to https://github.com/trezor/trezor-firmware/issues/3280 + model: [T2T1, T3B1, T3T1] + # T3B1 fails due to https://github.com/trezor/trezor-firmware/issues/3280 # remove after single global layout is implemented (or bug above fixed): exclude: - - model: T2B1 + - model: T3B1 env: COVERAGE_THRESHOLD: ${{ matrix.model == 'T2T1' && 78 || 77 }} steps: @@ -690,7 +723,7 @@ jobs: fi - name: Upload diff from main branch run: | - aws s3 sync master_diff s3://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }} + aws s3 sync --no-progress master_diff s3://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }} continue-on-error: true core_ui_comment: @@ -706,13 +739,16 @@ jobs: git diff --quiet origin/main...HEAD -- tests/ui_tests/fixtures.json || echo "FIXTURES_CHANGED=$?" >> $GITHUB_OUTPUT id: check-fixtures-changed - uses: ./.github/actions/ui-comment + # TODO: always run if comment already exists if: ${{ steps.check-fixtures-changed.outputs.FIXTURES_CHANGED == '1' }} core_upload_emu: name: Upload emulator binaries if: github.event_name == 'schedule' runs-on: ubuntu-latest - needs: core_emu + needs: + - core_emu + - core_emu_arm steps: - uses: actions/download-artifact@v4 with: @@ -726,7 +762,7 @@ jobs: continue-on-error: true - run: | rm unix/trezor-emu-core - aws s3 sync unix s3://data.trezor.io/dev/firmware/emu-nightly + aws s3 sync --no-progress unix s3://data.trezor.io/dev/firmware/emu-nightly # Connect # TODO: core_connect_test diff --git a/.github/workflows/legacy.yml b/.github/workflows/legacy.yml index d3eb4e98da..a9a51efd1d 100644 --- a/.github/workflows/legacy.yml +++ b/.github/workflows/legacy.yml @@ -74,6 +74,34 @@ jobs: legacy/firmware/trezor-emu-legacy* retention-days: 7 + legacy_emu_arm: + if: github.event_name == 'schedule' + name: Emulator arm + runs-on: ubuntu-latest-arm64 + strategy: + matrix: + coins: [universal] + type: [debuglink] + asan: ${{ fromJSON(github.event_name == 'schedule' && '["noasan", "asan"]' || '["noasan"]') }} + env: + EMULATOR: 1 + BITCOIN_ONLY: ${{ matrix.coins == 'universal' && '0' || '1' }} + DEBUG_LINK: ${{ matrix.type == 'debuglink' && '1' || '0' }} + ADDRESS_SANITIZER: ${{ matrix.asan == 'asan' && '1' || '0' }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: ./.github/actions/environment + - run: nix-shell --run "poetry run legacy/script/cibuild" + - run: mv legacy/firmware/trezor.elf legacy/firmware/trezor-emu-arm-legacy-T1B1-${{ matrix.coins }} + - uses: actions/upload-artifact@v4 + with: + name: legacy-emu-arm-${{ matrix.coins }}-${{ matrix.type }}-${{ matrix.asan }} + path: | + legacy/firmware/trezor-emu-arm-legacy* + retention-days: 7 + legacy_device_test: name: Device test runs-on: ubuntu-latest @@ -183,7 +211,7 @@ jobs: fi - name: Upload main branch diff run: | - aws s3 sync master_diff s3://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }} + aws s3 sync --no-progress master_diff s3://data.trezor.io/dev/firmware/master_diff/${{ github.run_id }} continue-on-error: true legacy_ui_comment: @@ -199,13 +227,16 @@ jobs: git diff --quiet origin/main...HEAD -- tests/ui_tests/fixtures.json || echo "FIXTURES_CHANGED=$?" >> $GITHUB_OUTPUT id: check-fixtures-changed - uses: ./.github/actions/ui-comment + # TODO: always run if comment already exists if: ${{ steps.check-fixtures-changed.outputs.FIXTURES_CHANGED == '1' }} - core_upload_emu: + legacy_upload_emu: name: Upload emulator binaries if: github.event_name == 'schedule' runs-on: ubuntu-latest - needs: legacy_emu + needs: + - legacy_emu + - legacy_emu_arm steps: - uses: actions/download-artifact@v4 with: @@ -219,5 +250,5 @@ jobs: continue-on-error: true - run: | mkdir emulators - cp trezor-emu-legacy* emulators - aws s3 sync emulators s3://data.trezor.io/dev/firmware/emu-nightly + cp trezor-emu-* emulators + aws s3 sync --no-progress emulators s3://data.trezor.io/dev/firmware/emu-nightly diff --git a/.github/workflows/prebuild.yml b/.github/workflows/prebuild.yml index 61b827c2b4..f6d1dfb26b 100644 --- a/.github/workflows/prebuild.yml +++ b/.github/workflows/prebuild.yml @@ -1,10 +1,15 @@ name: "Prebuild checks" -on: [pull_request] +on: + pull_request: + workflow_dispatch: + schedule: + - cron: '13 23 * * *' # every day @ 23:13 jobs: block-fixup: name: Block fixup + if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -54,7 +59,7 @@ jobs: # or contain `[no changelog]` in the commit message. changelog_check: name: Changelog check - if: ${{ github.ref != 'main' }} + if: ${{ github.ref != 'main' && github.event_name == 'pull_request' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.pylintrc b/.pylintrc index e47f2bc6c9..cefee09d88 100644 --- a/.pylintrc +++ b/.pylintrc @@ -35,3 +35,4 @@ enable= useless-else-on-loop, useless-object-inheritance, async-awaitable-return, + internal-model-tuple-comparison, diff --git a/Makefile b/Makefile index 04503bf02b..1daba0dad5 100644 --- a/Makefile +++ b/Makefile @@ -143,11 +143,17 @@ docs_summary_check: ## check if there are unlinked documentation files python3 tools/check_docs_summary.py vendorheader: ## generate vendor header - ./core/embed/vendorheader/generate.sh --quiet + ./core/tools/generate_vendorheader.sh --quiet vendorheader_check: ## check that vendor header is up to date - ./core/embed/vendorheader/generate.sh --quiet --check + ./core/tools/generate_vendorheader.sh --quiet --check -gen: templates mocks icons protobuf ci_docs vendorheader solana_templates ## regenerate auto-generated files from sources +bootloader_hashes: ## generate bootloader hashes + ./core/tools/bootloader_hashes.py -gen_check: templates_check mocks_check icons_check protobuf_check ci_docs_check vendorheader_check solana_templates_check ## check validity of auto-generated files +bootloader_hashes_check: ## check generated bootloader hashes + ./core/tools/bootloader_hashes.py --check + +gen: templates mocks icons protobuf ci_docs vendorheader solana_templates bootloader_hashes ## regenerate auto-generated files from sources + +gen_check: templates_check mocks_check icons_check protobuf_check ci_docs_check vendorheader_check solana_templates_check bootloader_hashes_check ## check validity of auto-generated files diff --git a/build-docker.sh b/build-docker.sh index 97982916fd..17c74ab710 100755 --- a/build-docker.sh +++ b/build-docker.sh @@ -69,7 +69,7 @@ OPT_BUILD_LEGACY=1 OPT_BUILD_NORMAL=1 OPT_BUILD_BITCOINONLY=1 INIT=1 -MODELS=(R T) +MODELS=(R T T3T1) CORE_TARGETS=(boardloader bootloader firmware) REPOSITORY="/local" diff --git a/ci/build.yml b/ci/build.yml index 95c6c145b8..8faa98da55 100644 --- a/ci/build.yml +++ b/ci/build.yml @@ -197,6 +197,8 @@ core unix regular build: stage: build <<: *gitlab_caching needs: [] + variables: + THP: "1" script: - $NIX_SHELL --run "poetry run make -C core build_unix" artifacts: diff --git a/ci/common_sync/common_repo_sync.sh b/ci/common_sync/common_repo_sync.sh index 904d526c64..e383283092 100755 --- a/ci/common_sync/common_repo_sync.sh +++ b/ci/common_sync/common_repo_sync.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash -GH_USER="$GH_TREZOR_BOT" -GH_TOKEN="$GH_TOKEN_COMMON_SYNC" +COMMON_REPO_TOKEN="$BOT_TOKEN" +COMMON_REPO_USER="$BOT_USERNAME" # checkout to temporary branch git checkout -B tmp # setup trezor-common remote -git remote add sync-common https://$GH_USER:$GH_TOKEN@github.com/trezor/trezor-common.git 2>/dev/null +git remote add sync-common https://$COMMON_REPO_USER:$COMMON_REPO_TOKEN@github.com/trezor/trezor-common.git 2>/dev/null # top commit in HEAD before monorepo was introduced TOP_COMMIT_IN_COMMON=893fd219d4a01bcffa0cd9cfa631856371ec5aa9 diff --git a/ci/deploy.yml b/ci/deploy.yml index 5a1cd06839..2cd163476b 100644 --- a/ci/deploy.yml +++ b/ci/deploy.yml @@ -324,20 +324,3 @@ sync emulators to aws: - branches # run for tags only tags: - deploy - -# common sync to trezor-common - -common sync: - stage: deploy - variables: - GIT_SUBMODULE_STRATEGY: "none" - GIT_STRATEGY: clone # clone entire repo instead of reusing workspace - GIT_DEPTH: 0 # avoid shallow clone - only: - - schedules - interruptible: false - needs: [] - before_script: [] # no poetry - script: - - echo "Synchronizing common with the trezor-common repository" - - ./ci/common_sync/common_repo_sync.sh diff --git a/ci/pyright/node-composition.nix b/ci/pyright/node-composition.nix index f929727d59..b795f708f1 100644 --- a/ci/pyright/node-composition.nix +++ b/ci/pyright/node-composition.nix @@ -1,12 +1,12 @@ -# This file has been generated by node2nix 1.9.0. Do not edit! +# This file has been generated by node2nix 1.11.1. Do not edit! {pkgs ? import { inherit system; - }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs-14_x"}: + }, system ? builtins.currentSystem, nodejs ? pkgs."nodejs_14"}: let nodeEnv = import ./node-env.nix { - inherit (pkgs) stdenv lib python2 runCommand writeTextFile; + inherit (pkgs) stdenv lib python2 runCommand writeTextFile writeShellScript; inherit pkgs nodejs; libtool = if pkgs.stdenv.isDarwin then pkgs.darwin.cctools else null; }; diff --git a/ci/pyright/node-env.nix b/ci/pyright/node-env.nix index 21089c4d54..bc1e36628a 100644 --- a/ci/pyright/node-env.nix +++ b/ci/pyright/node-env.nix @@ -1,6 +1,6 @@ # This file originates from node2nix -{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile}: +{lib, stdenv, nodejs, python2, pkgs, libtool, runCommand, writeTextFile, writeShellScript}: let # Workaround to cope with utillinux in Nixpkgs 20.09 and util-linux in Nixpkgs master @@ -40,36 +40,22 @@ let ''; }; - includeDependencies = {dependencies}: - lib.optionalString (dependencies != []) - (lib.concatMapStrings (dependency: - '' - # Bundle the dependencies of the package - mkdir -p node_modules - cd node_modules - - # Only include dependencies if they don't exist. They may also be bundled in the package. - if [ ! -e "${dependency.name}" ] - then - ${composePackage dependency} - fi + # Common shell logic + installPackage = writeShellScript "install-package" '' + installPackage() { + local packageName=$1 src=$2 - cd .. - '' - ) dependencies); + local strippedName - # Recursively composes the dependencies of a package - composePackage = { name, packageName, src, dependencies ? [], ... }@args: - builtins.addErrorContext "while evaluating node package '${packageName}'" '' - DIR=$(pwd) + local DIR=$PWD cd $TMPDIR - unpackFile ${src} + unpackFile $src # Make the base dir in which the target dependency resides first - mkdir -p "$(dirname "$DIR/${packageName}")" + mkdir -p "$(dirname "$DIR/$packageName")" - if [ -f "${src}" ] + if [ -f "$src" ] then # Figure out what directory has been unpacked packageDir="$(find . -maxdepth 1 -type d | tail -1)" @@ -79,28 +65,53 @@ let chmod -R u+w "$packageDir" # Move the extracted tarball into the output folder - mv "$packageDir" "$DIR/${packageName}" - elif [ -d "${src}" ] + mv "$packageDir" "$DIR/$packageName" + elif [ -d "$src" ] then # Get a stripped name (without hash) of the source directory. # On old nixpkgs it's already set internally. if [ -z "$strippedName" ] then - strippedName="$(stripHash ${src})" + strippedName="$(stripHash $src)" fi # Restore write permissions to make building work chmod -R u+w "$strippedName" # Move the extracted directory into the output folder - mv "$strippedName" "$DIR/${packageName}" + mv "$strippedName" "$DIR/$packageName" fi - # Unset the stripped name to not confuse the next unpack step - unset strippedName + # Change to the package directory to install dependencies + cd "$DIR/$packageName" + } + ''; + + # Bundle the dependencies of the package + # + # Only include dependencies if they don't exist. They may also be bundled in the package. + includeDependencies = {dependencies}: + lib.optionalString (dependencies != []) ( + '' + mkdir -p node_modules + cd node_modules + '' + + (lib.concatMapStrings (dependency: + '' + if [ ! -e "${dependency.packageName}" ]; then + ${composePackage dependency} + fi + '' + ) dependencies) + + '' + cd .. + '' + ); - # Include the dependencies of the package - cd "$DIR/${packageName}" + # Recursively composes the dependencies of a package + composePackage = { name, packageName, src, dependencies ? [], ... }@args: + builtins.addErrorContext "while evaluating node package '${packageName}'" '' + installPackage "${packageName}" "${src}" ${includeDependencies { inherit dependencies; }} cd .. ${lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."} @@ -154,7 +165,11 @@ let if(process.argv[2] == "development") { replaceDependencies(packageObj.devDependencies); } + else { + packageObj.devDependencies = {}; + } replaceDependencies(packageObj.optionalDependencies); + replaceDependencies(packageObj.peerDependencies); /* Write the fixed package.json file */ fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2)); @@ -246,8 +261,8 @@ let var packageLock = JSON.parse(fs.readFileSync("./package-lock.json")); if(![1, 2].includes(packageLock.lockfileVersion)) { - process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n"); - process.exit(1); + process.stderr.write("Sorry, I only understand lock file versions 1 and 2!\n"); + process.exit(1); } if(packageLock.dependencies !== undefined) { @@ -259,7 +274,7 @@ let # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes reconstructPackageLock = writeTextFile { - name = "addintegrityfields.js"; + name = "reconstructpackagelock.js"; text = '' var fs = require('fs'); var path = require('path'); @@ -269,25 +284,43 @@ let var lockObj = { name: packageObj.name, version: packageObj.version, - lockfileVersion: 1, + lockfileVersion: 2, requires: true, + packages: { + "": { + name: packageObj.name, + version: packageObj.version, + license: packageObj.license, + bin: packageObj.bin, + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + } + }, dependencies: {} }; - function augmentPackageJSON(filePath, dependencies) { + function augmentPackageJSON(filePath, packages, dependencies) { var packageJSON = path.join(filePath, "package.json"); if(fs.existsSync(packageJSON)) { var packageObj = JSON.parse(fs.readFileSync(packageJSON)); + packages[filePath] = { + version: packageObj.version, + integrity: "sha1-000000000000000000000000000=", + dependencies: packageObj.dependencies, + engines: packageObj.engines, + optionalDependencies: packageObj.optionalDependencies + }; dependencies[packageObj.name] = { version: packageObj.version, integrity: "sha1-000000000000000000000000000=", dependencies: {} }; - processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies); + processDependencies(path.join(filePath, "node_modules"), packages, dependencies[packageObj.name].dependencies); } } - function processDependencies(dir, dependencies) { + function processDependencies(dir, packages, dependencies) { if(fs.existsSync(dir)) { var files = fs.readdirSync(dir); @@ -303,23 +336,84 @@ let pkgFiles.forEach(function(entry) { if(stats.isDirectory()) { var pkgFilePath = path.join(filePath, entry); - augmentPackageJSON(pkgFilePath, dependencies); + augmentPackageJSON(pkgFilePath, packages, dependencies); } }); } else { - augmentPackageJSON(filePath, dependencies); + augmentPackageJSON(filePath, packages, dependencies); } } }); } } - processDependencies("node_modules", lockObj.dependencies); + processDependencies("node_modules", lockObj.packages, lockObj.dependencies); fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2)); ''; }; + # Script that links bins defined in package.json to the node_modules bin directory + # NPM does not do this for top-level packages itself anymore as of v7 + linkBinsScript = writeTextFile { + name = "linkbins.js"; + text = '' + var fs = require('fs'); + var path = require('path'); + + var packageObj = JSON.parse(fs.readFileSync("package.json")); + + var nodeModules = Array(packageObj.name.split("/").length).fill("..").join(path.sep); + + if(packageObj.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + if(typeof packageObj.bin == "object") { + Object.keys(packageObj.bin).forEach(function(exe) { + if(fs.existsSync(packageObj.bin[exe])) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin[exe]), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + else { + if(fs.existsSync(packageObj.bin)) { + console.log("linking bin '" + packageObj.bin + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.bin), + path.join(nodeModules, ".bin", packageObj.name.split("/").pop()) + ); + } + else { + console.log("skipping non-existent bin '" + packageObj.bin + "'"); + } + } + } + else if(packageObj.directories !== undefined && packageObj.directories.bin !== undefined) { + fs.mkdirSync(path.join(nodeModules, ".bin")) + + fs.readdirSync(packageObj.directories.bin).forEach(function(exe) { + if(fs.existsSync(path.join(packageObj.directories.bin, exe))) { + console.log("linking bin '" + exe + "'"); + fs.symlinkSync( + path.join("..", packageObj.name, packageObj.directories.bin, exe), + path.join(nodeModules, ".bin", exe) + ); + } + else { + console.log("skipping non-existent bin '" + exe + "'"); + } + }) + } + ''; + }; + prepareAndInvokeNPM = {packageName, bypassCache, reconstructLock, npmFlags, production}: let forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com"; @@ -366,20 +460,25 @@ let npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} rebuild + runHook postRebuild + if [ "''${dontNpmInstall-}" != "1" ] then # NPM tries to download packages even when they already exist if npm-shrinkwrap is used. rm -f npm-shrinkwrap.json - npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${lib.optionalString production "--production"} install + npm ${forceOfflineFlag} --nodedir=${nodeSources} --no-bin-links --ignore-scripts ${npmFlags} ${lib.optionalString production "--production"} install fi + + # Link executables defined in package.json + node ${linkBinsScript} ''; # Builds and composes an NPM package including all its dependencies buildNodePackage = { name , packageName - , version + , version ? null , dependencies ? [] , buildInputs ? [] , production ? true @@ -398,7 +497,7 @@ let extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" "meta" ]; in stdenv.mkDerivation ({ - name = "${name}-${version}"; + name = "${name}${if version == null then "" else "-${version}"}"; buildInputs = [ tarWrapper python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ lib.optional (stdenv.isDarwin) libtool @@ -415,6 +514,8 @@ let passAsFile = [ "compositionScript" "pinpointDependenciesScript" ]; installPhase = '' + source ${installPackage} + # Create and enter a root node_modules/ folder mkdir -p $out/lib/node_modules cd $out/lib/node_modules @@ -428,6 +529,17 @@ let if [ -d "$out/lib/node_modules/.bin" ] then ln -s $out/lib/node_modules/.bin $out/bin + + # Fixup all executables + ls $out/bin/* | while read i + do + file="$(readlink -f "$i")" + chmod u+rwx "$file" + if isScript "$file" + then + sed -i 's/\r$//' "$file" # convert crlf to lf + fi + done fi # Create symlinks to the deployed manual page folders, if applicable @@ -458,7 +570,7 @@ let buildNodeDependencies = { name , packageName - , version + , version ? null , src , dependencies ? [] , buildInputs ? [] @@ -476,7 +588,7 @@ let extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ]; in stdenv.mkDerivation ({ - name = "node-dependencies-${name}-${version}"; + name = "node-dependencies-${name}${if version == null then "" else "-${version}"}"; buildInputs = [ tarWrapper python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux @@ -492,6 +604,8 @@ let passAsFile = [ "includeScript" "pinpointDependenciesScript" ]; installPhase = '' + source ${installPackage} + mkdir -p $out/${packageName} cd $out/${packageName} @@ -504,6 +618,7 @@ let if [ -f ${src}/package-lock.json ] then cp ${src}/package-lock.json . + chmod 644 package-lock.json fi ''} @@ -526,7 +641,7 @@ let buildNodeShell = { name , packageName - , version + , version ? null , src , dependencies ? [] , buildInputs ? [] @@ -542,9 +657,10 @@ let let nodeDependencies = buildNodeDependencies args; + extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "unpackPhase" "buildPhase" ]; in - stdenv.mkDerivation { - name = "node-shell-${name}-${version}"; + stdenv.mkDerivation ({ + name = "node-shell-${name}${if version == null then "" else "-${version}"}"; buildInputs = [ python nodejs ] ++ lib.optional (stdenv.isLinux) utillinux ++ buildInputs; buildCommand = '' @@ -563,7 +679,7 @@ let export NODE_PATH=${nodeDependencies}/lib/node_modules export PATH="${nodeDependencies}/bin:$PATH" ''; - }; + } // extraArgs); in { buildNodeSourceDist = lib.makeOverridable buildNodeSourceDist; diff --git a/ci/pyright/node-packages.nix b/ci/pyright/node-packages.nix index 64c739c8f2..62202884d9 100644 --- a/ci/pyright/node-packages.nix +++ b/ci/pyright/node-packages.nix @@ -1,16 +1,70 @@ -# This file has been generated by node2nix 1.9.0. Do not edit! +# This file has been generated by node2nix 1.11.1. Do not edit! {nodeEnv, fetchurl, fetchgit, nix-gitignore, stdenv, lib, globalBuildInputs ? []}: let sources = { - "@discoveryjs/json-ext-0.5.6" = { + "@discoveryjs/json-ext-0.5.7" = { name = "_at_discoveryjs_slash_json-ext"; packageName = "@discoveryjs/json-ext"; - version = "0.5.6"; + version = "0.5.7"; src = fetchurl { - url = "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz"; - sha512 = "ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA=="; + url = "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz"; + sha512 = "dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="; + }; + }; + "@jridgewell/gen-mapping-0.3.5" = { + name = "_at_jridgewell_slash_gen-mapping"; + packageName = "@jridgewell/gen-mapping"; + version = "0.3.5"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz"; + sha512 = "IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg=="; + }; + }; + "@jridgewell/resolve-uri-3.1.2" = { + name = "_at_jridgewell_slash_resolve-uri"; + packageName = "@jridgewell/resolve-uri"; + version = "3.1.2"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz"; + sha512 = "bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="; + }; + }; + "@jridgewell/set-array-1.2.1" = { + name = "_at_jridgewell_slash_set-array"; + packageName = "@jridgewell/set-array"; + version = "1.2.1"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz"; + sha512 = "R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="; + }; + }; + "@jridgewell/source-map-0.3.6" = { + name = "_at_jridgewell_slash_source-map"; + packageName = "@jridgewell/source-map"; + version = "0.3.6"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz"; + sha512 = "1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ=="; + }; + }; + "@jridgewell/sourcemap-codec-1.4.15" = { + name = "_at_jridgewell_slash_sourcemap-codec"; + packageName = "@jridgewell/sourcemap-codec"; + version = "1.4.15"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz"; + sha512 = "eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="; + }; + }; + "@jridgewell/trace-mapping-0.3.25" = { + name = "_at_jridgewell_slash_trace-mapping"; + packageName = "@jridgewell/trace-mapping"; + version = "0.3.25"; + src = fetchurl { + url = "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz"; + sha512 = "vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ=="; }; }; "@nodelib/fs.scandir-2.1.5" = { @@ -40,220 +94,211 @@ let sha512 = "oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="; }; }; - "@types/copy-webpack-plugin-8.0.1" = { - name = "_at_types_slash_copy-webpack-plugin"; - packageName = "@types/copy-webpack-plugin"; - version = "8.0.1"; - src = fetchurl { - url = "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-8.0.1.tgz"; - sha512 = "TwEeGse0/wq+t3SFW0DEwroMS/cDkwVZT+vj7tMAYTp7llt/yz6NuW2n04X2M5P/kSfBQOORhrHAN2mqZdmybg=="; - }; - }; - "@types/eslint-8.2.1" = { + "@types/eslint-8.56.10" = { name = "_at_types_slash_eslint"; packageName = "@types/eslint"; - version = "8.2.1"; + version = "8.56.10"; src = fetchurl { - url = "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz"; - sha512 = "UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ=="; + url = "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz"; + sha512 = "Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ=="; }; }; - "@types/eslint-scope-3.7.2" = { + "@types/eslint-scope-3.7.7" = { name = "_at_types_slash_eslint-scope"; packageName = "@types/eslint-scope"; - version = "3.7.2"; + version = "3.7.7"; src = fetchurl { - url = "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz"; - sha512 = "TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ=="; + url = "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz"; + sha512 = "MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg=="; }; }; - "@types/estree-0.0.50" = { + "@types/estree-1.0.5" = { name = "_at_types_slash_estree"; packageName = "@types/estree"; - version = "0.0.50"; + version = "1.0.5"; src = fetchurl { - url = "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz"; - sha512 = "C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw=="; + url = "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz"; + sha512 = "/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="; }; }; - "@types/json-schema-7.0.9" = { + "@types/json-schema-7.0.15" = { name = "_at_types_slash_json-schema"; packageName = "@types/json-schema"; - version = "7.0.9"; + version = "7.0.15"; src = fetchurl { - url = "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz"; - sha512 = "qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="; + url = "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"; + sha512 = "5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="; }; }; - "@types/node-12.20.41" = { + "@types/node-17.0.45" = { name = "_at_types_slash_node"; packageName = "@types/node"; - version = "12.20.41"; + version = "17.0.45"; src = fetchurl { - url = "https://registry.npmjs.org/@types/node/-/node-12.20.41.tgz"; - sha512 = "f6xOqucbDirG7LOzedpvzjP3UTmHttRou3Mosx3vL9wr9AIQGhcPgVnqa8ihpZYnxyM1rxeNCvTyukPKZtq10Q=="; + url = "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz"; + sha512 = "w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="; }; }; - "@webassemblyjs/ast-1.11.1" = { + "@webassemblyjs/ast-1.12.1" = { name = "_at_webassemblyjs_slash_ast"; packageName = "@webassemblyjs/ast"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz"; - sha512 = "ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw=="; + url = "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz"; + sha512 = "EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg=="; }; }; - "@webassemblyjs/floating-point-hex-parser-1.11.1" = { + "@webassemblyjs/floating-point-hex-parser-1.11.6" = { name = "_at_webassemblyjs_slash_floating-point-hex-parser"; packageName = "@webassemblyjs/floating-point-hex-parser"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz"; - sha512 = "iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ=="; + url = "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz"; + sha512 = "ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw=="; }; }; - "@webassemblyjs/helper-api-error-1.11.1" = { + "@webassemblyjs/helper-api-error-1.11.6" = { name = "_at_webassemblyjs_slash_helper-api-error"; packageName = "@webassemblyjs/helper-api-error"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz"; - sha512 = "RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg=="; + url = "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz"; + sha512 = "o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="; }; }; - "@webassemblyjs/helper-buffer-1.11.1" = { + "@webassemblyjs/helper-buffer-1.12.1" = { name = "_at_webassemblyjs_slash_helper-buffer"; packageName = "@webassemblyjs/helper-buffer"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz"; - sha512 = "gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA=="; + url = "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz"; + sha512 = "nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="; }; }; - "@webassemblyjs/helper-numbers-1.11.1" = { + "@webassemblyjs/helper-numbers-1.11.6" = { name = "_at_webassemblyjs_slash_helper-numbers"; packageName = "@webassemblyjs/helper-numbers"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz"; - sha512 = "vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ=="; + url = "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz"; + sha512 = "vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g=="; }; }; - "@webassemblyjs/helper-wasm-bytecode-1.11.1" = { + "@webassemblyjs/helper-wasm-bytecode-1.11.6" = { name = "_at_webassemblyjs_slash_helper-wasm-bytecode"; packageName = "@webassemblyjs/helper-wasm-bytecode"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz"; - sha512 = "PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q=="; + url = "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz"; + sha512 = "sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="; }; }; - "@webassemblyjs/helper-wasm-section-1.11.1" = { + "@webassemblyjs/helper-wasm-section-1.12.1" = { name = "_at_webassemblyjs_slash_helper-wasm-section"; packageName = "@webassemblyjs/helper-wasm-section"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz"; - sha512 = "10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg=="; + url = "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz"; + sha512 = "Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g=="; }; }; - "@webassemblyjs/ieee754-1.11.1" = { + "@webassemblyjs/ieee754-1.11.6" = { name = "_at_webassemblyjs_slash_ieee754"; packageName = "@webassemblyjs/ieee754"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz"; - sha512 = "hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ=="; + url = "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz"; + sha512 = "LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg=="; }; }; - "@webassemblyjs/leb128-1.11.1" = { + "@webassemblyjs/leb128-1.11.6" = { name = "_at_webassemblyjs_slash_leb128"; packageName = "@webassemblyjs/leb128"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz"; - sha512 = "BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw=="; + url = "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz"; + sha512 = "m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ=="; }; }; - "@webassemblyjs/utf8-1.11.1" = { + "@webassemblyjs/utf8-1.11.6" = { name = "_at_webassemblyjs_slash_utf8"; packageName = "@webassemblyjs/utf8"; - version = "1.11.1"; + version = "1.11.6"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz"; - sha512 = "9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ=="; + url = "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz"; + sha512 = "vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="; }; }; - "@webassemblyjs/wasm-edit-1.11.1" = { + "@webassemblyjs/wasm-edit-1.12.1" = { name = "_at_webassemblyjs_slash_wasm-edit"; packageName = "@webassemblyjs/wasm-edit"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz"; - sha512 = "g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA=="; + url = "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz"; + sha512 = "1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g=="; }; }; - "@webassemblyjs/wasm-gen-1.11.1" = { + "@webassemblyjs/wasm-gen-1.12.1" = { name = "_at_webassemblyjs_slash_wasm-gen"; packageName = "@webassemblyjs/wasm-gen"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz"; - sha512 = "F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA=="; + url = "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz"; + sha512 = "TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w=="; }; }; - "@webassemblyjs/wasm-opt-1.11.1" = { + "@webassemblyjs/wasm-opt-1.12.1" = { name = "_at_webassemblyjs_slash_wasm-opt"; packageName = "@webassemblyjs/wasm-opt"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz"; - sha512 = "VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw=="; + url = "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz"; + sha512 = "Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg=="; }; }; - "@webassemblyjs/wasm-parser-1.11.1" = { + "@webassemblyjs/wasm-parser-1.12.1" = { name = "_at_webassemblyjs_slash_wasm-parser"; packageName = "@webassemblyjs/wasm-parser"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz"; - sha512 = "rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA=="; + url = "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz"; + sha512 = "xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ=="; }; }; - "@webassemblyjs/wast-printer-1.11.1" = { + "@webassemblyjs/wast-printer-1.12.1" = { name = "_at_webassemblyjs_slash_wast-printer"; packageName = "@webassemblyjs/wast-printer"; - version = "1.11.1"; + version = "1.12.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz"; - sha512 = "IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg=="; + url = "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz"; + sha512 = "+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA=="; }; }; - "@webpack-cli/configtest-1.1.0" = { + "@webpack-cli/configtest-2.1.1" = { name = "_at_webpack-cli_slash_configtest"; packageName = "@webpack-cli/configtest"; - version = "1.1.0"; + version = "2.1.1"; src = fetchurl { - url = "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz"; - sha512 = "ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg=="; + url = "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz"; + sha512 = "wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw=="; }; }; - "@webpack-cli/info-1.4.0" = { + "@webpack-cli/info-2.0.2" = { name = "_at_webpack-cli_slash_info"; packageName = "@webpack-cli/info"; - version = "1.4.0"; + version = "2.0.2"; src = fetchurl { - url = "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz"; - sha512 = "F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw=="; + url = "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz"; + sha512 = "zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A=="; }; }; - "@webpack-cli/serve-1.6.0" = { + "@webpack-cli/serve-2.0.5" = { name = "_at_webpack-cli_slash_serve"; packageName = "@webpack-cli/serve"; - version = "1.6.0"; + version = "2.0.5"; src = fetchurl { - url = "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz"; - sha512 = "ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA=="; + url = "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz"; + sha512 = "lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ=="; }; }; "@xtuc/ieee754-1.2.0" = { @@ -274,22 +319,22 @@ let sha512 = "NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="; }; }; - "acorn-8.7.0" = { + "acorn-8.11.3" = { name = "acorn"; packageName = "acorn"; - version = "8.7.0"; + version = "8.11.3"; src = fetchurl { - url = "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz"; - sha512 = "V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="; + url = "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz"; + sha512 = "Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg=="; }; }; - "acorn-import-assertions-1.8.0" = { + "acorn-import-assertions-1.9.0" = { name = "acorn-import-assertions"; packageName = "acorn-import-assertions"; - version = "1.8.0"; + version = "1.9.0"; src = fetchurl { - url = "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz"; - sha512 = "m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw=="; + url = "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz"; + sha512 = "cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA=="; }; }; "ajv-6.12.6" = { @@ -301,6 +346,24 @@ let sha512 = "j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="; }; }; + "ajv-8.13.0" = { + name = "ajv"; + packageName = "ajv"; + version = "8.13.0"; + src = fetchurl { + url = "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz"; + sha512 = "PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA=="; + }; + }; + "ajv-formats-2.1.1" = { + name = "ajv-formats"; + packageName = "ajv-formats"; + version = "2.1.1"; + src = fetchurl { + url = "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz"; + sha512 = "Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="; + }; + }; "ajv-keywords-3.5.2" = { name = "ajv-keywords"; packageName = "ajv-keywords"; @@ -310,6 +373,15 @@ let sha512 = "5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="; }; }; + "ajv-keywords-5.1.0" = { + name = "ajv-keywords"; + packageName = "ajv-keywords"; + version = "5.1.0"; + src = fetchurl { + url = "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz"; + sha512 = "YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="; + }; + }; "ansi-styles-4.3.0" = { name = "ansi-styles"; packageName = "ansi-styles"; @@ -319,15 +391,6 @@ let sha512 = "zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="; }; }; - "array-union-2.1.0" = { - name = "array-union"; - packageName = "array-union"; - version = "2.1.0"; - src = fetchurl { - url = "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"; - sha512 = "HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="; - }; - }; "balanced-match-1.0.2" = { name = "balanced-match"; packageName = "balanced-match"; @@ -337,6 +400,15 @@ let sha512 = "3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="; }; }; + "big.js-5.2.2" = { + name = "big.js"; + packageName = "big.js"; + version = "5.2.2"; + src = fetchurl { + url = "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"; + sha512 = "vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="; + }; + }; "brace-expansion-1.1.11" = { name = "brace-expansion"; packageName = "brace-expansion"; @@ -355,13 +427,13 @@ let sha512 = "b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="; }; }; - "browserslist-4.19.1" = { + "browserslist-4.23.0" = { name = "browserslist"; packageName = "browserslist"; - version = "4.19.1"; + version = "4.23.0"; src = fetchurl { - url = "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz"; - sha512 = "u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A=="; + url = "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz"; + sha512 = "QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ=="; }; }; "buffer-from-1.1.2" = { @@ -373,13 +445,13 @@ let sha512 = "E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="; }; }; - "caniuse-lite-1.0.30001296" = { + "caniuse-lite-1.0.30001615" = { name = "caniuse-lite"; packageName = "caniuse-lite"; - version = "1.0.30001296"; + version = "1.0.30001615"; src = fetchurl { - url = "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz"; - sha512 = "WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q=="; + url = "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001615.tgz"; + sha512 = "1IpazM5G3r38meiae0bHRnPhz+CBQ3ZLqbQMtrg+AsTPKAXgW38JNsXkyZ+v8waCsDmPq87lmfun5Q2AGysNEQ=="; }; }; "chalk-4.1.2" = { @@ -427,31 +499,31 @@ let sha512 = "dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="; }; }; - "colorette-2.0.16" = { + "colorette-2.0.20" = { name = "colorette"; packageName = "colorette"; - version = "2.0.16"; + version = "2.0.20"; src = fetchurl { - url = "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz"; - sha512 = "hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="; + url = "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz"; + sha512 = "IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w=="; }; }; - "commander-2.20.3" = { + "commander-10.0.1" = { name = "commander"; packageName = "commander"; - version = "2.20.3"; + version = "10.0.1"; src = fetchurl { - url = "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"; - sha512 = "GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="; + url = "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz"; + sha512 = "y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug=="; }; }; - "commander-7.2.0" = { + "commander-2.20.3" = { name = "commander"; packageName = "commander"; - version = "7.2.0"; + version = "2.20.3"; src = fetchurl { - url = "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"; - sha512 = "QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="; + url = "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"; + sha512 = "GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="; }; }; "concat-map-0.0.1" = { @@ -460,16 +532,16 @@ let version = "0.0.1"; src = fetchurl { url = "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"; - sha1 = "d8a96bd77fd68df7793a73036a3ba0d5405d477b"; + sha512 = "/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="; }; }; - "copy-webpack-plugin-9.1.0" = { + "copy-webpack-plugin-11.0.0" = { name = "copy-webpack-plugin"; packageName = "copy-webpack-plugin"; - version = "9.1.0"; + version = "11.0.0"; src = fetchurl { - url = "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-9.1.0.tgz"; - sha512 = "rxnR7PaGigJzhqETHGmAcxKnLZSR5u1Y3/bcIv/1FnqXedcL/E2ewK7ZCNrArJKCiSv8yVXhTqetJh8inDvfsA=="; + url = "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz"; + sha512 = "fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ=="; }; }; "cross-spawn-7.0.3" = { @@ -490,49 +562,76 @@ let sha512 = "WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="; }; }; - "electron-to-chromium-1.4.36" = { + "electron-to-chromium-1.4.754" = { name = "electron-to-chromium"; packageName = "electron-to-chromium"; - version = "1.4.36"; + version = "1.4.754"; + src = fetchurl { + url = "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.754.tgz"; + sha512 = "7Kr5jUdns5rL/M9wFFmMZAgFDuL2YOnanFH4OI4iFzUqyh3XOL7nAGbSlSMZdzKMIyyTpNSbqZsWG9odwLeKvA=="; + }; + }; + "emojis-list-3.0.0" = { + name = "emojis-list"; + packageName = "emojis-list"; + version = "3.0.0"; src = fetchurl { - url = "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.36.tgz"; - sha512 = "MbLlbF39vKrXWlFEFpCgDHwdlz4O3LmHM5W4tiLRHjSmEUXjJjz8sZkMgWgvYxlZw3N1iDTmCEtOkkESb5TMCg=="; + url = "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz"; + sha512 = "/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="; }; }; - "enhanced-resolve-5.8.3" = { + "enhanced-resolve-5.16.0" = { name = "enhanced-resolve"; packageName = "enhanced-resolve"; - version = "5.8.3"; + version = "5.16.0"; src = fetchurl { - url = "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz"; - sha512 = "EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA=="; + url = "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz"; + sha512 = "O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA=="; }; }; - "envinfo-7.8.1" = { + "envinfo-7.13.0" = { name = "envinfo"; packageName = "envinfo"; - version = "7.8.1"; + version = "7.13.0"; src = fetchurl { - url = "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz"; - sha512 = "/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw=="; + url = "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz"; + sha512 = "cvcaMr7KqXVh4nyzGTVqTum+gAiL265x5jUWQIDLq//zOGbW+gSW/C+OWLleY/rs9Qole6AZLMXPbtIFQbqu+Q=="; }; }; - "es-module-lexer-0.9.3" = { + "es-module-lexer-1.5.2" = { name = "es-module-lexer"; packageName = "es-module-lexer"; - version = "0.9.3"; + version = "1.5.2"; + src = fetchurl { + url = "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.2.tgz"; + sha512 = "l60ETUTmLqbVbVHv1J4/qj+M8nq7AwMzEcg3kmJDt9dCNrTk+yHcYFf/Kw75pMDwd9mPcIGCG5LcS20SxYRzFA=="; + }; + }; + "esbuild-0.19.12" = { + name = "esbuild"; + packageName = "esbuild"; + version = "0.19.12"; + src = fetchurl { + url = "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz"; + sha512 = "aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg=="; + }; + }; + "esbuild-loader-3.2.0" = { + name = "esbuild-loader"; + packageName = "esbuild-loader"; + version = "3.2.0"; src = fetchurl { - url = "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz"; - sha512 = "1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ=="; + url = "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-3.2.0.tgz"; + sha512 = "lnIdRMQpk50alCa0QoW0ozc0D3rjJXl02mtMsk9INIcW25RPZhDja332bu85ixwVNbhQ7VfBRcQyZ/qza8mWiA=="; }; }; - "escalade-3.1.1" = { + "escalade-3.1.2" = { name = "escalade"; packageName = "escalade"; - version = "3.1.1"; + version = "3.1.2"; src = fetchurl { - url = "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"; - sha512 = "k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="; + url = "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz"; + sha512 = "ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA=="; }; }; "eslint-scope-5.1.1" = { @@ -580,15 +679,6 @@ let sha512 = "mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="; }; }; - "execa-5.1.1" = { - name = "execa"; - packageName = "execa"; - version = "5.1.1"; - src = fetchurl { - url = "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz"; - sha512 = "8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="; - }; - }; "fast-deep-equal-3.1.3" = { name = "fast-deep-equal"; packageName = "fast-deep-equal"; @@ -598,13 +688,13 @@ let sha512 = "f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="; }; }; - "fast-glob-3.2.7" = { + "fast-glob-3.3.2" = { name = "fast-glob"; packageName = "fast-glob"; - version = "3.2.7"; + version = "3.3.2"; src = fetchurl { - url = "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz"; - sha512 = "rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q=="; + url = "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz"; + sha512 = "oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow=="; }; }; "fast-json-stable-stringify-2.1.0" = { @@ -616,22 +706,22 @@ let sha512 = "lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="; }; }; - "fastest-levenshtein-1.0.12" = { + "fastest-levenshtein-1.0.16" = { name = "fastest-levenshtein"; packageName = "fastest-levenshtein"; - version = "1.0.12"; + version = "1.0.16"; src = fetchurl { - url = "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz"; - sha512 = "On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow=="; + url = "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz"; + sha512 = "eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg=="; }; }; - "fastq-1.13.0" = { + "fastq-1.17.1" = { name = "fastq"; packageName = "fastq"; - version = "1.13.0"; + version = "1.17.1"; src = fetchurl { - url = "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz"; - sha512 = "YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="; + url = "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz"; + sha512 = "sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w=="; }; }; "fill-range-7.0.1" = { @@ -652,40 +742,49 @@ let sha512 = "PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="; }; }; + "flat-5.0.2" = { + name = "flat"; + packageName = "flat"; + version = "5.0.2"; + src = fetchurl { + url = "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz"; + sha512 = "b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ=="; + }; + }; "fs.realpath-1.0.0" = { name = "fs.realpath"; packageName = "fs.realpath"; version = "1.0.0"; src = fetchurl { url = "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"; - sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f"; + sha512 = "OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="; }; }; - "function-bind-1.1.1" = { + "function-bind-1.1.2" = { name = "function-bind"; packageName = "function-bind"; - version = "1.1.1"; + version = "1.1.2"; src = fetchurl { - url = "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"; - sha512 = "yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="; + url = "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"; + sha512 = "7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="; }; }; - "get-stream-6.0.1" = { - name = "get-stream"; - packageName = "get-stream"; - version = "6.0.1"; + "get-tsconfig-4.7.3" = { + name = "get-tsconfig"; + packageName = "get-tsconfig"; + version = "4.7.3"; src = fetchurl { - url = "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz"; - sha512 = "ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="; + url = "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz"; + sha512 = "ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg=="; }; }; - "glob-7.2.0" = { + "glob-7.2.3" = { name = "glob"; packageName = "glob"; - version = "7.2.0"; + version = "7.2.3"; src = fetchurl { - url = "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz"; - sha512 = "lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="; + url = "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz"; + sha512 = "nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="; }; }; "glob-parent-5.1.2" = { @@ -715,31 +814,22 @@ let sha512 = "lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="; }; }; - "globby-11.0.4" = { + "globby-13.2.2" = { name = "globby"; packageName = "globby"; - version = "11.0.4"; + version = "13.2.2"; src = fetchurl { - url = "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz"; - sha512 = "9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg=="; + url = "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz"; + sha512 = "Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w=="; }; }; - "graceful-fs-4.2.9" = { + "graceful-fs-4.2.11" = { name = "graceful-fs"; packageName = "graceful-fs"; - version = "4.2.9"; + version = "4.2.11"; src = fetchurl { - url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"; - sha512 = "NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="; - }; - }; - "has-1.0.3" = { - name = "has"; - packageName = "has"; - version = "1.0.3"; - src = fetchurl { - url = "https://registry.npmjs.org/has/-/has-1.0.3.tgz"; - sha512 = "f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="; + url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz"; + sha512 = "RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="; }; }; "has-flag-4.0.0" = { @@ -751,22 +841,22 @@ let sha512 = "EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="; }; }; - "human-signals-2.1.0" = { - name = "human-signals"; - packageName = "human-signals"; - version = "2.1.0"; + "hasown-2.0.2" = { + name = "hasown"; + packageName = "hasown"; + version = "2.0.2"; src = fetchurl { - url = "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"; - sha512 = "B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="; + url = "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz"; + sha512 = "0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="; }; }; - "ignore-5.2.0" = { + "ignore-5.3.1" = { name = "ignore"; packageName = "ignore"; - version = "5.2.0"; + version = "5.3.1"; src = fetchurl { - url = "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"; - sha512 = "CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="; + url = "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz"; + sha512 = "5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw=="; }; }; "import-local-3.1.0" = { @@ -784,7 +874,7 @@ let version = "1.0.6"; src = fetchurl { url = "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"; - sha1 = "49bd6331d7d02d0c09bc910a1075ba8165b56df9"; + sha512 = "k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="; }; }; "inherits-2.0.4" = { @@ -805,22 +895,22 @@ let sha512 = "agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="; }; }; - "interpret-2.2.0" = { + "interpret-3.1.1" = { name = "interpret"; packageName = "interpret"; - version = "2.2.0"; + version = "3.1.1"; src = fetchurl { - url = "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz"; - sha512 = "Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="; + url = "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz"; + sha512 = "6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ=="; }; }; - "is-core-module-2.8.1" = { + "is-core-module-2.13.1" = { name = "is-core-module"; packageName = "is-core-module"; - version = "2.8.1"; + version = "2.13.1"; src = fetchurl { - url = "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz"; - sha512 = "SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA=="; + url = "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz"; + sha512 = "hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw=="; }; }; "is-extglob-2.1.1" = { @@ -829,7 +919,7 @@ let version = "2.1.1"; src = fetchurl { url = "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"; - sha1 = "a88c02535791f02ed37c76a1b9ea9773c833f8c2"; + sha512 = "SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="; }; }; "is-glob-4.0.3" = { @@ -859,22 +949,13 @@ let sha512 = "h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="; }; }; - "is-stream-2.0.1" = { - name = "is-stream"; - packageName = "is-stream"; - version = "2.0.1"; - src = fetchurl { - url = "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz"; - sha512 = "hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="; - }; - }; "isexe-2.0.0" = { name = "isexe"; packageName = "isexe"; version = "2.0.0"; src = fetchurl { url = "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"; - sha1 = "e8fbf374dc556ff8947a10dcb0572d633f2cfa10"; + sha512 = "RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="; }; }; "isobject-3.0.1" = { @@ -883,25 +964,25 @@ let version = "3.0.1"; src = fetchurl { url = "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz"; - sha1 = "4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"; + sha512 = "WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg=="; }; }; - "jest-worker-27.4.6" = { + "jest-worker-27.5.1" = { name = "jest-worker"; packageName = "jest-worker"; - version = "27.4.6"; + version = "27.5.1"; src = fetchurl { - url = "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz"; - sha512 = "gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw=="; + url = "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz"; + sha512 = "7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg=="; }; }; - "json-parse-better-errors-1.0.2" = { - name = "json-parse-better-errors"; - packageName = "json-parse-better-errors"; - version = "1.0.2"; + "json-parse-even-better-errors-2.3.1" = { + name = "json-parse-even-better-errors"; + packageName = "json-parse-even-better-errors"; + version = "2.3.1"; src = fetchurl { - url = "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz"; - sha512 = "mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="; + url = "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"; + sha512 = "xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="; }; }; "json-schema-traverse-0.4.1" = { @@ -913,6 +994,24 @@ let sha512 = "xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="; }; }; + "json-schema-traverse-1.0.0" = { + name = "json-schema-traverse"; + packageName = "json-schema-traverse"; + version = "1.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz"; + sha512 = "NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="; + }; + }; + "json5-2.2.3" = { + name = "json5"; + packageName = "json5"; + version = "2.2.3"; + src = fetchurl { + url = "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz"; + sha512 = "XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="; + }; + }; "kind-of-6.0.3" = { name = "kind-of"; packageName = "kind-of"; @@ -922,13 +1021,22 @@ let sha512 = "dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="; }; }; - "loader-runner-4.2.0" = { + "loader-runner-4.3.0" = { name = "loader-runner"; packageName = "loader-runner"; - version = "4.2.0"; + version = "4.3.0"; + src = fetchurl { + url = "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz"; + sha512 = "3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg=="; + }; + }; + "loader-utils-2.0.4" = { + name = "loader-utils"; + packageName = "loader-utils"; + version = "2.0.4"; src = fetchurl { - url = "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz"; - sha512 = "92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="; + url = "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz"; + sha512 = "xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw=="; }; }; "locate-path-5.0.0" = { @@ -967,58 +1075,49 @@ let sha512 = "8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="; }; }; - "micromatch-4.0.4" = { + "micromatch-4.0.5" = { name = "micromatch"; packageName = "micromatch"; - version = "4.0.4"; + version = "4.0.5"; src = fetchurl { - url = "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz"; - sha512 = "pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg=="; + url = "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz"; + sha512 = "DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA=="; }; }; - "mime-db-1.51.0" = { + "mime-db-1.52.0" = { name = "mime-db"; packageName = "mime-db"; - version = "1.51.0"; + version = "1.52.0"; src = fetchurl { - url = "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz"; - sha512 = "5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="; + url = "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"; + sha512 = "sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="; }; }; - "mime-types-2.1.34" = { + "mime-types-2.1.35" = { name = "mime-types"; packageName = "mime-types"; - version = "2.1.34"; - src = fetchurl { - url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz"; - sha512 = "6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A=="; - }; - }; - "mimic-fn-2.1.0" = { - name = "mimic-fn"; - packageName = "mimic-fn"; - version = "2.1.0"; + version = "2.1.35"; src = fetchurl { - url = "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"; - sha512 = "OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="; + url = "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"; + sha512 = "ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="; }; }; - "minimatch-3.0.4" = { + "minimatch-3.1.2" = { name = "minimatch"; packageName = "minimatch"; - version = "3.0.4"; + version = "3.1.2"; src = fetchurl { - url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"; - sha512 = "yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="; + url = "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz"; + sha512 = "J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="; }; }; - "minimist-1.2.5" = { + "minimist-1.2.8" = { name = "minimist"; packageName = "minimist"; - version = "1.2.5"; + version = "1.2.8"; src = fetchurl { - url = "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"; - sha512 = "FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="; + url = "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz"; + sha512 = "2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="; }; }; "neo-async-2.6.2" = { @@ -1030,13 +1129,13 @@ let sha512 = "Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="; }; }; - "node-releases-2.0.1" = { + "node-releases-2.0.14" = { name = "node-releases"; packageName = "node-releases"; - version = "2.0.1"; + version = "2.0.14"; src = fetchurl { - url = "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz"; - sha512 = "CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="; + url = "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz"; + sha512 = "y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw=="; }; }; "normalize-path-3.0.0" = { @@ -1048,31 +1147,13 @@ let sha512 = "6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="; }; }; - "npm-run-path-4.0.1" = { - name = "npm-run-path"; - packageName = "npm-run-path"; - version = "4.0.1"; - src = fetchurl { - url = "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"; - sha512 = "S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="; - }; - }; "once-1.4.0" = { name = "once"; packageName = "once"; version = "1.4.0"; src = fetchurl { url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz"; - sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1"; - }; - }; - "onetime-5.1.2" = { - name = "onetime"; - packageName = "onetime"; - version = "5.1.2"; - src = fetchurl { - url = "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"; - sha512 = "kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="; + sha512 = "lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="; }; }; "p-limit-2.3.0" = { @@ -1117,7 +1198,7 @@ let version = "1.0.1"; src = fetchurl { url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"; - sha1 = "174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"; + sha512 = "AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="; }; }; "path-key-3.1.1" = { @@ -1174,13 +1255,13 @@ let sha512 = "HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="; }; }; - "punycode-2.1.1" = { + "punycode-2.3.1" = { name = "punycode"; packageName = "punycode"; - version = "2.1.1"; + version = "2.3.1"; src = fetchurl { - url = "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"; - sha512 = "XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="; + url = "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"; + sha512 = "vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="; }; }; "queue-microtask-1.2.3" = { @@ -1207,25 +1288,34 @@ let version = "0.6.2"; src = fetchurl { url = "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz"; - sha1 = "85204b54dba82d5742e28c96756ef43af50e3384"; + sha512 = "HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw=="; }; }; - "rechoir-0.7.1" = { + "rechoir-0.8.0" = { name = "rechoir"; packageName = "rechoir"; - version = "0.7.1"; + version = "0.8.0"; + src = fetchurl { + url = "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz"; + sha512 = "/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="; + }; + }; + "require-from-string-2.0.2" = { + name = "require-from-string"; + packageName = "require-from-string"; + version = "2.0.2"; src = fetchurl { - url = "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz"; - sha512 = "/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg=="; + url = "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"; + sha512 = "Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="; }; }; - "resolve-1.21.0" = { + "resolve-1.22.8" = { name = "resolve"; packageName = "resolve"; - version = "1.21.0"; + version = "1.22.8"; src = fetchurl { - url = "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"; - sha512 = "3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="; + url = "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz"; + sha512 = "oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw=="; }; }; "resolve-cwd-3.0.0" = { @@ -1246,6 +1336,15 @@ let sha512 = "qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="; }; }; + "resolve-pkg-maps-1.0.0" = { + name = "resolve-pkg-maps"; + packageName = "resolve-pkg-maps"; + version = "1.0.0"; + src = fetchurl { + url = "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz"; + sha512 = "seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="; + }; + }; "reusify-1.0.4" = { name = "reusify"; packageName = "reusify"; @@ -1273,31 +1372,40 @@ let sha512 = "rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="; }; }; - "schema-utils-3.1.1" = { + "schema-utils-3.3.0" = { name = "schema-utils"; packageName = "schema-utils"; - version = "3.1.1"; + version = "3.3.0"; src = fetchurl { - url = "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"; - sha512 = "Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw=="; + url = "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz"; + sha512 = "pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg=="; }; }; - "semver-7.3.5" = { + "schema-utils-4.2.0" = { + name = "schema-utils"; + packageName = "schema-utils"; + version = "4.2.0"; + src = fetchurl { + url = "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz"; + sha512 = "L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw=="; + }; + }; + "semver-7.6.0" = { name = "semver"; packageName = "semver"; - version = "7.3.5"; + version = "7.6.0"; src = fetchurl { - url = "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz"; - sha512 = "PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ=="; + url = "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz"; + sha512 = "EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg=="; }; }; - "serialize-javascript-6.0.0" = { + "serialize-javascript-6.0.2" = { name = "serialize-javascript"; packageName = "serialize-javascript"; - version = "6.0.0"; + version = "6.0.2"; src = fetchurl { - url = "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz"; - sha512 = "Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag=="; + url = "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz"; + sha512 = "Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g=="; }; }; "shallow-clone-3.0.1" = { @@ -1327,40 +1435,40 @@ let sha512 = "7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="; }; }; - "shelljs-0.8.4" = { + "shelljs-0.8.5" = { name = "shelljs"; packageName = "shelljs"; - version = "0.8.4"; + version = "0.8.5"; src = fetchurl { - url = "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz"; - sha512 = "7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ=="; + url = "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz"; + sha512 = "TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow=="; }; }; - "shx-0.3.3" = { + "shx-0.3.4" = { name = "shx"; packageName = "shx"; - version = "0.3.3"; + version = "0.3.4"; src = fetchurl { - url = "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz"; - sha512 = "nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA=="; + url = "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz"; + sha512 = "N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g=="; }; }; - "signal-exit-3.0.6" = { - name = "signal-exit"; - packageName = "signal-exit"; - version = "3.0.6"; + "slash-4.0.0" = { + name = "slash"; + packageName = "slash"; + version = "4.0.0"; src = fetchurl { - url = "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz"; - sha512 = "sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="; + url = "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"; + sha512 = "3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew=="; }; }; - "slash-3.0.0" = { - name = "slash"; - packageName = "slash"; - version = "3.0.0"; + "source-list-map-2.0.1" = { + name = "source-list-map"; + packageName = "source-list-map"; + version = "2.0.1"; src = fetchurl { - url = "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"; - sha512 = "g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="; + url = "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz"; + sha512 = "qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="; }; }; "source-map-0.6.1" = { @@ -1372,13 +1480,13 @@ let sha512 = "UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="; }; }; - "source-map-0.7.3" = { + "source-map-0.7.4" = { name = "source-map"; packageName = "source-map"; - version = "0.7.3"; + version = "0.7.4"; src = fetchurl { - url = "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz"; - sha512 = "CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="; + url = "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz"; + sha512 = "l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA=="; }; }; "source-map-support-0.5.21" = { @@ -1390,15 +1498,6 @@ let sha512 = "uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="; }; }; - "strip-final-newline-2.0.0" = { - name = "strip-final-newline"; - packageName = "strip-final-newline"; - version = "2.0.0"; - src = fetchurl { - url = "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"; - sha512 = "BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="; - }; - }; "supports-color-7.2.0" = { name = "supports-color"; packageName = "supports-color"; @@ -1435,22 +1534,22 @@ let sha512 = "GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="; }; }; - "terser-5.10.0" = { + "terser-5.31.0" = { name = "terser"; packageName = "terser"; - version = "5.10.0"; + version = "5.31.0"; src = fetchurl { - url = "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz"; - sha512 = "AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA=="; + url = "https://registry.npmjs.org/terser/-/terser-5.31.0.tgz"; + sha512 = "Q1JFAoUKE5IMfI4Z/lkE/E6+SwgzO+x4tq4v1AyBLRj8VSYvRO6A/rQrPg1yud4g0En9EKI1TvFRF2tQFcoUkg=="; }; }; - "terser-webpack-plugin-5.3.0" = { + "terser-webpack-plugin-5.3.10" = { name = "terser-webpack-plugin"; packageName = "terser-webpack-plugin"; - version = "5.3.0"; + version = "5.3.10"; src = fetchurl { - url = "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz"; - sha512 = "LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ=="; + url = "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz"; + sha512 = "BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w=="; }; }; "to-regex-range-5.0.1" = { @@ -1462,22 +1561,31 @@ let sha512 = "65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="; }; }; - "ts-loader-9.2.6" = { + "ts-loader-9.5.1" = { name = "ts-loader"; packageName = "ts-loader"; - version = "9.2.6"; + version = "9.5.1"; src = fetchurl { - url = "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz"; - sha512 = "QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw=="; + url = "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz"; + sha512 = "rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg=="; }; }; - "typescript-4.4.4" = { + "typescript-5.2.2" = { name = "typescript"; packageName = "typescript"; - version = "4.4.4"; + version = "5.2.2"; + src = fetchurl { + url = "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz"; + sha512 = "mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="; + }; + }; + "update-browserslist-db-1.0.14" = { + name = "update-browserslist-db"; + packageName = "update-browserslist-db"; + version = "1.0.14"; src = fetchurl { - url = "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz"; - sha512 = "DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA=="; + url = "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.14.tgz"; + sha512 = "JixKH8GR2pWYshIPUg/NujK3JO7JiqEEUiNArE86NQyrgUuZeTlZQN3xuS/yiV5Kb48ev9K6RqNkaJjXsdg7Jw=="; }; }; "uri-js-4.4.1" = { @@ -1489,49 +1597,58 @@ let sha512 = "7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="; }; }; - "watchpack-2.3.1" = { + "watchpack-2.4.1" = { name = "watchpack"; packageName = "watchpack"; - version = "2.3.1"; + version = "2.4.1"; src = fetchurl { - url = "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz"; - sha512 = "x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA=="; + url = "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz"; + sha512 = "8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg=="; }; }; - "webpack-5.65.0" = { + "webpack-5.91.0" = { name = "webpack"; packageName = "webpack"; - version = "5.65.0"; + version = "5.91.0"; src = fetchurl { - url = "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz"; - sha512 = "Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw=="; + url = "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz"; + sha512 = "rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw=="; }; }; - "webpack-cli-4.9.1" = { + "webpack-cli-5.1.4" = { name = "webpack-cli"; packageName = "webpack-cli"; - version = "4.9.1"; + version = "5.1.4"; src = fetchurl { - url = "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz"; - sha512 = "JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ=="; + url = "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz"; + sha512 = "pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg=="; }; }; - "webpack-merge-5.8.0" = { + "webpack-merge-5.10.0" = { name = "webpack-merge"; packageName = "webpack-merge"; - version = "5.8.0"; + version = "5.10.0"; src = fetchurl { - url = "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz"; - sha512 = "/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q=="; + url = "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz"; + sha512 = "+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA=="; }; }; - "webpack-sources-3.2.2" = { + "webpack-sources-1.4.3" = { name = "webpack-sources"; packageName = "webpack-sources"; - version = "3.2.2"; + version = "1.4.3"; src = fetchurl { - url = "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.2.tgz"; - sha512 = "cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw=="; + url = "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz"; + sha512 = "lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ=="; + }; + }; + "webpack-sources-3.2.3" = { + name = "webpack-sources"; + packageName = "webpack-sources"; + version = "3.2.3"; + src = fetchurl { + url = "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz"; + sha512 = "/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w=="; }; }; "which-2.0.2" = { @@ -1543,13 +1660,13 @@ let sha512 = "BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="; }; }; - "wildcard-2.0.0" = { + "wildcard-2.0.1" = { name = "wildcard"; packageName = "wildcard"; - version = "2.0.0"; + version = "2.0.1"; src = fetchurl { - url = "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz"; - sha512 = "JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw=="; + url = "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz"; + sha512 = "CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ=="; }; }; "wrappy-1.0.2" = { @@ -1558,7 +1675,7 @@ let version = "1.0.2"; src = fetchurl { url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"; - sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"; + sha512 = "l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="; }; }; "yallist-4.0.0" = { @@ -1573,73 +1690,82 @@ let }; in { - "pyright-1.1.204" = nodeEnv.buildNodePackage { + "pyright-1.1.361" = nodeEnv.buildNodePackage { name = "pyright"; packageName = "pyright"; - version = "1.1.204"; + version = "1.1.361"; src = fetchurl { - url = "https://registry.npmjs.org/pyright/-/pyright-1.1.204.tgz"; - sha512 = "vzk+w1Awf0RMd4f5EUjeR/18F9TJFokatg6n/NNYkBdgVnFHWOxyqWMrsWyrbkpBRV6/TKZ3W1h79oAvwsYydQ=="; + url = "https://registry.npmjs.org/pyright/-/pyright-1.1.361.tgz"; + sha512 = "cu4VrXoA7zYg2TdFgh/IkQhD+Jc3GaEK5P/Vatptd7h40hC6S/fZZya8eZMnLZ0n09PBks8VM9IVRK4+X5zG3w=="; }; dependencies = [ - sources."@discoveryjs/json-ext-0.5.6" + sources."@discoveryjs/json-ext-0.5.7" + sources."@jridgewell/gen-mapping-0.3.5" + sources."@jridgewell/resolve-uri-3.1.2" + sources."@jridgewell/set-array-1.2.1" + sources."@jridgewell/source-map-0.3.6" + sources."@jridgewell/sourcemap-codec-1.4.15" + sources."@jridgewell/trace-mapping-0.3.25" sources."@nodelib/fs.scandir-2.1.5" sources."@nodelib/fs.stat-2.0.5" sources."@nodelib/fs.walk-1.2.8" - sources."@types/copy-webpack-plugin-8.0.1" - sources."@types/eslint-8.2.1" - sources."@types/eslint-scope-3.7.2" - sources."@types/estree-0.0.50" - sources."@types/json-schema-7.0.9" - sources."@types/node-12.20.41" - sources."@webassemblyjs/ast-1.11.1" - sources."@webassemblyjs/floating-point-hex-parser-1.11.1" - sources."@webassemblyjs/helper-api-error-1.11.1" - sources."@webassemblyjs/helper-buffer-1.11.1" - sources."@webassemblyjs/helper-numbers-1.11.1" - sources."@webassemblyjs/helper-wasm-bytecode-1.11.1" - sources."@webassemblyjs/helper-wasm-section-1.11.1" - sources."@webassemblyjs/ieee754-1.11.1" - sources."@webassemblyjs/leb128-1.11.1" - sources."@webassemblyjs/utf8-1.11.1" - sources."@webassemblyjs/wasm-edit-1.11.1" - sources."@webassemblyjs/wasm-gen-1.11.1" - sources."@webassemblyjs/wasm-opt-1.11.1" - sources."@webassemblyjs/wasm-parser-1.11.1" - sources."@webassemblyjs/wast-printer-1.11.1" - sources."@webpack-cli/configtest-1.1.0" - sources."@webpack-cli/info-1.4.0" - sources."@webpack-cli/serve-1.6.0" + sources."@types/eslint-8.56.10" + sources."@types/eslint-scope-3.7.7" + sources."@types/estree-1.0.5" + sources."@types/json-schema-7.0.15" + sources."@types/node-17.0.45" + sources."@webassemblyjs/ast-1.12.1" + sources."@webassemblyjs/floating-point-hex-parser-1.11.6" + sources."@webassemblyjs/helper-api-error-1.11.6" + sources."@webassemblyjs/helper-buffer-1.12.1" + sources."@webassemblyjs/helper-numbers-1.11.6" + sources."@webassemblyjs/helper-wasm-bytecode-1.11.6" + sources."@webassemblyjs/helper-wasm-section-1.12.1" + sources."@webassemblyjs/ieee754-1.11.6" + sources."@webassemblyjs/leb128-1.11.6" + sources."@webassemblyjs/utf8-1.11.6" + sources."@webassemblyjs/wasm-edit-1.12.1" + sources."@webassemblyjs/wasm-gen-1.12.1" + sources."@webassemblyjs/wasm-opt-1.12.1" + sources."@webassemblyjs/wasm-parser-1.12.1" + sources."@webassemblyjs/wast-printer-1.12.1" + sources."@webpack-cli/configtest-2.1.1" + sources."@webpack-cli/info-2.0.2" + sources."@webpack-cli/serve-2.0.5" sources."@xtuc/ieee754-1.2.0" sources."@xtuc/long-4.2.2" - sources."acorn-8.7.0" - sources."acorn-import-assertions-1.8.0" - sources."ajv-6.12.6" - sources."ajv-keywords-3.5.2" + sources."acorn-8.11.3" + sources."acorn-import-assertions-1.9.0" + sources."ajv-8.13.0" + sources."ajv-formats-2.1.1" + sources."ajv-keywords-5.1.0" sources."ansi-styles-4.3.0" - sources."array-union-2.1.0" sources."balanced-match-1.0.2" + sources."big.js-5.2.2" sources."brace-expansion-1.1.11" sources."braces-3.0.2" - sources."browserslist-4.19.1" + sources."browserslist-4.23.0" sources."buffer-from-1.1.2" - sources."caniuse-lite-1.0.30001296" + sources."caniuse-lite-1.0.30001615" sources."chalk-4.1.2" sources."chrome-trace-event-1.0.3" sources."clone-deep-4.0.1" sources."color-convert-2.0.1" sources."color-name-1.1.4" - sources."colorette-2.0.16" + sources."colorette-2.0.20" sources."commander-2.20.3" sources."concat-map-0.0.1" - sources."copy-webpack-plugin-9.1.0" + sources."copy-webpack-plugin-11.0.0" sources."cross-spawn-7.0.3" sources."dir-glob-3.0.1" - sources."electron-to-chromium-1.4.36" - sources."enhanced-resolve-5.8.3" - sources."envinfo-7.8.1" - sources."es-module-lexer-0.9.3" - sources."escalade-3.1.1" + sources."electron-to-chromium-1.4.754" + sources."emojis-list-3.0.0" + sources."enhanced-resolve-5.16.0" + sources."envinfo-7.13.0" + sources."es-module-lexer-1.5.2" + sources."esbuild-0.19.12" + sources."esbuild-loader-3.2.0" + sources."escalade-3.1.2" sources."eslint-scope-5.1.1" (sources."esrecurse-4.3.0" // { dependencies = [ @@ -1648,67 +1774,64 @@ in }) sources."estraverse-4.3.0" sources."events-3.3.0" - sources."execa-5.1.1" sources."fast-deep-equal-3.1.3" - (sources."fast-glob-3.2.7" // { + (sources."fast-glob-3.3.2" // { dependencies = [ sources."glob-parent-5.1.2" ]; }) sources."fast-json-stable-stringify-2.1.0" - sources."fastest-levenshtein-1.0.12" - sources."fastq-1.13.0" + sources."fastest-levenshtein-1.0.16" + sources."fastq-1.17.1" sources."fill-range-7.0.1" sources."find-up-4.1.0" + sources."flat-5.0.2" sources."fs.realpath-1.0.0" - sources."function-bind-1.1.1" - sources."get-stream-6.0.1" - sources."glob-7.2.0" + sources."function-bind-1.1.2" + sources."get-tsconfig-4.7.3" + sources."glob-7.2.3" sources."glob-parent-6.0.2" sources."glob-to-regexp-0.4.1" - sources."globby-11.0.4" - sources."graceful-fs-4.2.9" - sources."has-1.0.3" + sources."globby-13.2.2" + sources."graceful-fs-4.2.11" sources."has-flag-4.0.0" - sources."human-signals-2.1.0" - sources."ignore-5.2.0" + sources."hasown-2.0.2" + sources."ignore-5.3.1" sources."import-local-3.1.0" sources."inflight-1.0.6" sources."inherits-2.0.4" sources."interpret-1.4.0" - sources."is-core-module-2.8.1" + sources."is-core-module-2.13.1" sources."is-extglob-2.1.1" sources."is-glob-4.0.3" sources."is-number-7.0.0" sources."is-plain-object-2.0.4" - sources."is-stream-2.0.1" sources."isexe-2.0.0" sources."isobject-3.0.1" - (sources."jest-worker-27.4.6" // { + (sources."jest-worker-27.5.1" // { dependencies = [ sources."supports-color-8.1.1" ]; }) - sources."json-parse-better-errors-1.0.2" - sources."json-schema-traverse-0.4.1" + sources."json-parse-even-better-errors-2.3.1" + sources."json-schema-traverse-1.0.0" + sources."json5-2.2.3" sources."kind-of-6.0.3" - sources."loader-runner-4.2.0" + sources."loader-runner-4.3.0" + sources."loader-utils-2.0.4" sources."locate-path-5.0.0" sources."lru-cache-6.0.0" sources."merge-stream-2.0.0" sources."merge2-1.4.1" - sources."micromatch-4.0.4" - sources."mime-db-1.51.0" - sources."mime-types-2.1.34" - sources."mimic-fn-2.1.0" - sources."minimatch-3.0.4" - sources."minimist-1.2.5" + sources."micromatch-4.0.5" + sources."mime-db-1.52.0" + sources."mime-types-2.1.35" + sources."minimatch-3.1.2" + sources."minimist-1.2.8" sources."neo-async-2.6.2" - sources."node-releases-2.0.1" + sources."node-releases-2.0.14" sources."normalize-path-3.0.0" - sources."npm-run-path-4.0.1" sources."once-1.4.0" - sources."onetime-5.1.2" sources."p-limit-2.3.0" sources."p-locate-4.1.0" sources."p-try-2.2.0" @@ -1720,55 +1843,72 @@ in sources."picocolors-1.0.0" sources."picomatch-2.3.1" sources."pkg-dir-4.2.0" - sources."punycode-2.1.1" + sources."punycode-2.3.1" sources."queue-microtask-1.2.3" sources."randombytes-2.1.0" sources."rechoir-0.6.2" - sources."resolve-1.21.0" + sources."require-from-string-2.0.2" + sources."resolve-1.22.8" sources."resolve-cwd-3.0.0" sources."resolve-from-5.0.0" + sources."resolve-pkg-maps-1.0.0" sources."reusify-1.0.4" sources."run-parallel-1.2.0" sources."safe-buffer-5.2.1" - sources."schema-utils-3.1.1" - sources."semver-7.3.5" - sources."serialize-javascript-6.0.0" + sources."schema-utils-4.2.0" + sources."semver-7.6.0" + sources."serialize-javascript-6.0.2" sources."shallow-clone-3.0.1" sources."shebang-command-2.0.0" sources."shebang-regex-3.0.0" - sources."shelljs-0.8.4" - sources."shx-0.3.3" - sources."signal-exit-3.0.6" - sources."slash-3.0.0" + sources."shelljs-0.8.5" + sources."shx-0.3.4" + sources."slash-4.0.0" + sources."source-list-map-2.0.1" sources."source-map-0.6.1" sources."source-map-support-0.5.21" - sources."strip-final-newline-2.0.0" sources."supports-color-7.2.0" sources."supports-preserve-symlinks-flag-1.0.0" sources."tapable-2.2.1" - (sources."terser-5.10.0" // { + sources."terser-5.31.0" + (sources."terser-webpack-plugin-5.3.10" // { dependencies = [ - sources."source-map-0.7.3" + sources."ajv-6.12.6" + sources."ajv-keywords-3.5.2" + sources."json-schema-traverse-0.4.1" + sources."schema-utils-3.3.0" ]; }) - sources."terser-webpack-plugin-5.3.0" sources."to-regex-range-5.0.1" - sources."ts-loader-9.2.6" - sources."typescript-4.4.4" + (sources."ts-loader-9.5.1" // { + dependencies = [ + sources."source-map-0.7.4" + ]; + }) + sources."typescript-5.2.2" + sources."update-browserslist-db-1.0.14" sources."uri-js-4.4.1" - sources."watchpack-2.3.1" - sources."webpack-5.65.0" - (sources."webpack-cli-4.9.1" // { + sources."watchpack-2.4.1" + (sources."webpack-5.91.0" // { + dependencies = [ + sources."ajv-6.12.6" + sources."ajv-keywords-3.5.2" + sources."json-schema-traverse-0.4.1" + sources."schema-utils-3.3.0" + sources."webpack-sources-3.2.3" + ]; + }) + (sources."webpack-cli-5.1.4" // { dependencies = [ - sources."commander-7.2.0" - sources."interpret-2.2.0" - sources."rechoir-0.7.1" + sources."commander-10.0.1" + sources."interpret-3.1.1" + sources."rechoir-0.8.0" ]; }) - sources."webpack-merge-5.8.0" - sources."webpack-sources-3.2.2" + sources."webpack-merge-5.10.0" + sources."webpack-sources-1.4.3" sources."which-2.0.2" - sources."wildcard-2.0.0" + sources."wildcard-2.0.1" sources."wrappy-1.0.2" sources."yallist-4.0.0" ]; diff --git a/ci/pyright/package.json b/ci/pyright/package.json index 2e148b9c55..dea304b2b6 100644 --- a/ci/pyright/package.json +++ b/ci/pyright/package.json @@ -1,3 +1,3 @@ [ - { "pyright": "1.1.204" } + { "pyright": "1.1.361" } ] diff --git a/ci/shell.nix b/ci/shell.nix index ba4770fa9a..f90b29130b 100644 --- a/ci/shell.nix +++ b/ci/shell.nix @@ -4,10 +4,10 @@ }: let - # the last commit from master as of 2023-04-14 + # the last commit from master as of 2024-01-22 rustOverlay = import (builtins.fetchTarball { - url = "https://github.com/oxalica/rust-overlay/archive/db7bf4a2dd295adeeaa809d36387098926a15487.tar.gz"; - sha256 = "0gk6kag09w8lyn9was8dpjgslxw5p81bx04379m9v6ky09kw482d"; + url = "https://github.com/oxalica/rust-overlay/archive/e36f66bb10b09f5189dc3b1706948eaeb9a1c555.tar.gz"; + sha256 = "1vivsmqmqajbvv7181y7mfl48fxmm75hq2c8rj6h1l2ymq28zcpg"; }); # define this variable and devTools if you want nrf{util,connect} acceptJlink = builtins.getEnv "TREZOR_FIRMWARE_ACCEPT_JLINK_LICENSE" == "yes"; @@ -22,6 +22,17 @@ let }; overlays = [ rustOverlay ]; }; + # 23.11 from 15. 4. 2024 + newNixpkgs = import (builtins.fetchTarball { + url = "https://github.com/NixOS/nixpkgs/archive/53a2c32bc66f5ae41a28d7a9a49d321172af621e.tar.gz"; + sha256 = "0yqbwqbripb1bbhlwjfbqmg9qb0lai2fc0k1vfh674d6rrc8igwv"; + }) { + config = { + allowUnfree = acceptJlink; + segger-jlink.acceptLicense = acceptJlink; + }; + overlays = [ rustOverlay ]; + }; # commit before python36 was removed oldPythonNixpkgs = import (builtins.fetchTarball { url = "https://github.com/NixOS/nixpkgs/archive/b9126f77f553974c90ab65520eff6655415fc5f4.tar.gz"; @@ -49,7 +60,7 @@ let done ''; # NOTE: don't forget to update Minimum Supported Rust Version in docs/core/build/emulator.md - rustProfiles = nixpkgs.rust-bin.nightly."2023-04-14"; + rustProfiles = nixpkgs.rust-bin.nightly."2024-01-21"; rustNightly = rustProfiles.minimal.override { targets = [ "thumbv7em-none-eabihf" # TT @@ -108,7 +119,7 @@ stdenvNoCC.mkDerivation ({ libffi libjpeg libusb1 - llvmPackages.clang + newNixpkgs.llvmPackages_17.clang openssl pkgconfig poetry @@ -120,7 +131,7 @@ stdenvNoCC.mkDerivation ({ moreutils ] ++ lib.optionals (!stdenv.isDarwin) [ autoPatchelfHook - gcc11 + gcc12 procps valgrind ] ++ lib.optionals (stdenv.isDarwin) [ diff --git a/common/defs/README.md b/common/defs/README.md index 6e30ef3c83..a57de51193 100644 --- a/common/defs/README.md +++ b/common/defs/README.md @@ -80,10 +80,10 @@ added to the dataset. # Support Information -We keep track of support status of each built-in coin over our devices. That is -`T1B1` for Trezor One, `T2T1` for Trezor T, `T2B1` for Trezor R, `connect` for [Connect](https://github.com/trezor/connect) -and `suite` for [Trezor Suite](https://suite.trezor.io/). In further description, the word "device" -applies to Connect and Suite as well. +We keep track of support status of each built-in coin over our devices. That is `T1B1` +for Trezor One, `T2T1` for Trezor T, `T2B1` and `T3B1` for Trezor Safe 3 (both models +should have identical entries, except for minimum versions which are higher on `T3B1`), +`T3T1` for Trezor Safe 5. This information is stored in [`support.json`](support.json). External contributors should not touch this file unless asked to. diff --git a/common/defs/blockchain_link.json b/common/defs/blockchain_link.json index ccc86f9e22..15cc7901b7 100644 --- a/common/defs/blockchain_link.json +++ b/common/defs/blockchain_link.json @@ -205,13 +205,6 @@ "https://eth2.trezor.io" ] }, - "eth:tROP": { - "type": "blockbook", - "url": [ - "https://ropsten1.trezor.io", - "https://ropsten2.trezor.io" - ] - }, "misc:XRP": { "type": "ripple", "url": [ @@ -237,5 +230,44 @@ "url": [ "wss://trezor-cardano-preview.blockfrost.io" ] + }, + "misc:SOL": { + "type": "solana", + "url": [ + "https://solana1.trezor.io", + "https://solana2.trezor.io", + "https://solana3.trezor.io", + "https://solana4.trezor.io" + ] + }, + "misc:DSOL": { + "type": "solana", + "url": [ + "https://solana-dev.trezor.io" + ] + }, + "eth:ETH:1": { + "type": "blockbook", + "url": ["https://eth1.trezor.io", "https://eth2.trezor.io"] + }, + "eth:BNB:56": { + "type": "blockbook", + "url": ["https://bsc1.trezor.io"] + }, + "eth:ETC:61": { + "type": "blockbook", + "url": ["https://etc1.trezor.io", "https://etc2.trezor.io"] + }, + "eth:MATIC:137": { + "type": "blockbook", + "url": ["https://matic1.trezor.io", "https://matic2.trezor.io"] + }, + "eth:tHOL:17000": { + "type": "blockbook", + "url": ["https://holesky1.trezor.io", "https://holesky2.trezor.io"] + }, + "eth:tSEP:11155111": { + "type": "blockbook", + "url": ["https://sepolia1.trezor.io"] } } diff --git a/common/defs/coins_details.json b/common/defs/coins_details.json deleted file mode 100644 index b1eb055656..0000000000 --- a/common/defs/coins_details.json +++ /dev/null @@ -1,41972 +0,0 @@ -{ - "coins": { - "bitcoin:ACM": { - "links": { - "Github": "https://github.com/Actinium-project/Actinium", - "Homepage": "https://actinium.org" - }, - "marketcap_usd": 180870, - "name": "Actinium", - "shortcut": "ACM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Actilectrum", - "url": "https://actilectrum.org" - } - ] - }, - "bitcoin:AXE": { - "links": { - "Github": "https://github.com/axerunners/axe", - "Homepage": "https://axerunners.com" - }, - "marketcap_usd": 20908, - "name": "Axe", - "shortcut": "AXE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-AXE", - "url": "https://github.com/AXErunners/electrum-axe" - } - ] - }, - "bitcoin:BCH": { - "links": { - "Github": "https://github.com/bitcoin-cash-node/bitcoin-cash-node", - "Homepage": "https://www.bitcoincash.org" - }, - "marketcap_usd": 2567934801, - "name": "Bitcoin Cash", - "shortcut": "BCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Electron Cash", - "url": "https://electroncash.org" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:BTC": { - "links": { - "Github": "https://github.com/bitcoin/bitcoin", - "Homepage": "https://bitcoin.org" - }, - "marketcap_usd": 451280107391, - "name": "Bitcoin", - "shortcut": "BTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Electrum", - "url": "https://electrum.org" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:BTCP": { - "links": { - "Github": "https://github.com/BTCPrivate/BitcoinPrivate", - "Homepage": "https://btcprivate.org" - }, - "marketcap_usd": 2118991, - "name": "Bitcoin Private", - "shortcut": "BTCP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "BTCP Electrum", - "url": "https://github.com/BTCPrivate/electrum-btcp" - } - ] - }, - "bitcoin:BTG": { - "links": { - "Github": "https://github.com/BTCGPU/BTCGPU", - "Homepage": "https://bitcoingold.org" - }, - "marketcap_usd": 297235948, - "name": "Bitcoin Gold", - "shortcut": "BTG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "ElectrumG", - "url": "https://github.com/BTCGPU/electrum" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:BTX": { - "links": { - "Github": "https://github.com/LIMXTEC/BitCore", - "Homepage": "https://bitcore.cc" - }, - "marketcap_usd": 1290295, - "name": "Bitcore", - "shortcut": "BTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-BTX", - "url": "https://github.com/LIMXTEC/electrum-btx" - } - ] - }, - "bitcoin:CPU": { - "links": { - "Github": "https://github.com/cpuchain/cpuchain", - "Homepage": "https://cpuchain.org" - }, - "marketcap_usd": 0, - "name": "CPUchain", - "shortcut": "CPU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-CPU", - "url": "https://cpuchain.org/download-page.html" - } - ] - }, - "bitcoin:CRW": { - "links": { - "Github": "https://github.com/Crowndev/crowncoin", - "Homepage": "https://crownplatform.com" - }, - "marketcap_usd": 227389, - "name": "Crown", - "shortcut": "CRW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Crown-Electrum", - "url": "https://github.com/Crowndev/crown-electrum" - } - ] - }, - "bitcoin:DASH": { - "links": { - "Github": "https://github.com/dashpay/dash", - "Homepage": "https://www.dash.org" - }, - "marketcap_usd": 801190219, - "name": "Dash", - "shortcut": "DASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "DMT", - "url": "https://github.com/Bertrand256/dash-masternode-tool" - }, - { - "name": "Dash Electrum", - "url": "https://electrum.dash.org" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:DCR": { - "links": { - "Github": "https://github.com/decred/dcrd", - "Homepage": "https://www.decred.org" - }, - "marketcap_usd": 353035595, - "name": "Decred", - "shortcut": "DCR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:DGB": { - "links": { - "Github": "https://github.com/digibyte/digibyte", - "Homepage": "https://digibyte.io" - }, - "marketcap_usd": 180666248, - "name": "DigiByte", - "shortcut": "DGB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:DOGE": { - "links": { - "Github": "https://github.com/dogecoin/dogecoin", - "Homepage": "https://dogecoin.com" - }, - "marketcap_usd": 10815053466, - "name": "Dogecoin", - "shortcut": "DOGE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:ELEMENTS": { - "links": { - "Github": "https://github.com/ElementsProject/elements", - "Homepage": "https://elementsproject.org" - }, - "marketcap_usd": 0, - "name": "Elements", - "shortcut": "ELEMENTS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [] - }, - "bitcoin:FIRO": { - "links": { - "Github": "https://github.com/firoorg/firo", - "Homepage": "https://firo.org" - }, - "marketcap_usd": 30581066, - "name": "Firo", - "shortcut": "FIRO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-FIRO", - "url": "https://github.com/firoorg/electrum-firo" - }, - { - "name": "Znode Tool", - "url": "https://github.com/firoorg/znode-tool-evo" - } - ] - }, - "bitcoin:FJC": { - "links": { - "Github": "https://github.com/fujicoin/fujicoin", - "Homepage": "https://fujicoin.org" - }, - "marketcap_usd": 0, - "name": "Fujicoin", - "shortcut": "FJC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-FJC", - "url": "http://www.fujicoin.org/downloads.php" - } - ] - }, - "bitcoin:FLO": { - "links": { - "Github": "https://github.com/floblockchain/flo", - "Homepage": "https://flo.cash" - }, - "marketcap_usd": 0, - "name": "Flo", - "shortcut": "FLO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Chaintek", - "url": "https://wallet.chaintek.net/" - } - ] - }, - "bitcoin:FTC": { - "links": { - "Github": "https://github.com/FeatherCoin/Feathercoin", - "Homepage": "https://feathercoin.com" - }, - "marketcap_usd": 1216847, - "name": "Feathercoin", - "shortcut": "FTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-FTC", - "url": "https://github.com/Feathercoin-Foundation/electrum-ftc" - } - ] - }, - "bitcoin:GRS": { - "links": { - "Github": "https://github.com/Groestlcoin/groestlcoin", - "Homepage": "https://www.groestlcoin.org" - }, - "marketcap_usd": 35812118, - "name": "Groestlcoin", - "shortcut": "GRS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-GRS", - "url": "https://www.groestlcoin.org/groestlcoin-electrum-wallet" - } - ] - }, - "bitcoin:KMD": { - "links": { - "Github": "https://github.com/komodoplatform/komodo", - "Homepage": "https://komodoplatform.com" - }, - "marketcap_usd": 40071524, - "name": "Komodo", - "shortcut": "KMD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "AtomicDEX", - "url": "https://app.atomicdex.io/" - } - ] - }, - "bitcoin:KOTO": { - "links": { - "Github": "https://github.com/KotoDevelopers/koto", - "Homepage": "https://ko-to.org" - }, - "marketcap_usd": 0, - "name": "Koto", - "shortcut": "KOTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-KOTO", - "url": "https://electrum.kotocoin.info" - } - ] - }, - "bitcoin:LTC": { - "links": { - "Github": "https://github.com/litecoin-project/litecoin", - "Homepage": "https://litecoin.org" - }, - "marketcap_usd": 6827206762, - "name": "Litecoin", - "shortcut": "LTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Electrum-LTC", - "url": "https://electrum-ltc.org" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "bitcoin:MONA": { - "links": { - "Github": "https://github.com/monacoinproject/monacoin", - "Homepage": "https://monacoin.org" - }, - "marketcap_usd": 32996960, - "name": "Monacoin", - "shortcut": "MONA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-MONA", - "url": "https://electrum-mona.org" - } - ] - }, - "bitcoin:NMC": { - "links": { - "Github": "https://github.com/namecoin/namecoin-core", - "Homepage": "https://namecoin.org" - }, - "marketcap_usd": 18207166, - "name": "Namecoin", - "shortcut": "NMC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Electrum-NMC", - "url": "https://github.com/namecoin/electrum-nmc" - } - ] - }, - "bitcoin:PPC": { - "links": { - "Github": "https://github.com/peercoin/peercoin", - "Homepage": "https://peercoin.net" - }, - "marketcap_usd": 12956306, - "name": "Peercoin", - "shortcut": "PPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [] - }, - "bitcoin:QTUM": { - "links": { - "Github": "https://github.com/qtumproject/qtum", - "Homepage": "https://qtum.org" - }, - "marketcap_usd": 349944403, - "name": "Qtum", - "shortcut": "QTUM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Qtum-Electrum", - "url": "https://github.com/qtumproject/qtum-electrum" - } - ] - }, - "bitcoin:RITO": { - "links": { - "Github": "https://github.com/RitoProject", - "Homepage": "https://ritocoin.org" - }, - "marketcap_usd": 41504, - "name": "Ritocoin", - "shortcut": "RITO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Chaintek", - "url": "https://wallet.chaintek.net/" - } - ] - }, - "bitcoin:RVN": { - "links": { - "Github": "https://github.com/RavenProject/Ravencoin", - "Homepage": "https://ravencoin.org" - }, - "marketcap_usd": 364652876, - "name": "Ravencoin", - "shortcut": "RVN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Chaintek", - "url": "https://wallet.chaintek.net/" - }, - { - "name": "Electrum-RVN", - "url": "https://github.com/traysi/electrum-raven" - } - ] - }, - "bitcoin:SMART": { - "links": { - "Github": "https://github.com/SmartCash/Core-Smart", - "Homepage": "https://smartcash.cc" - }, - "marketcap_usd": 831180, - "name": "SmartCash", - "shortcut": "SMART", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-SMART", - "url": "https://github.com/smartcash/electrum-smart" - } - ] - }, - "bitcoin:SYS": { - "links": { - "Github": "https://github.com/syscoin/syscoin", - "Homepage": "https://syscoin.org" - }, - "marketcap_usd": 135689538, - "name": "Syscoin", - "shortcut": "SYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-SYS", - "url": "https://github.com/syscoin/electrum" - } - ] - }, - "bitcoin:UNO": { - "links": { - "Github": "https://github.com/unobtanium-official/unobtanium", - "Homepage": "https://unobtanium.uno" - }, - "marketcap_usd": 0, - "name": "Unobtanium", - "shortcut": "UNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-UNO", - "url": "https://github.com/flurbos/electrum-uno" - } - ] - }, - "bitcoin:VIA": { - "links": { - "Github": "https://github.com/viacoin", - "Homepage": "https://viacoin.org" - }, - "marketcap_usd": 1208142, - "name": "Viacoin", - "shortcut": "VIA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Vialectrum", - "url": "https://vialectrum.org" - } - ] - }, - "bitcoin:VIPS": { - "links": { - "Github": "https://github.com/VIPSTARCOIN/VIPSTARCOIN", - "Homepage": "https://vipstarcoin.jp" - }, - "marketcap_usd": 0, - "name": "VIPSTARCOIN", - "shortcut": "VIPS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-VIPS", - "url": "https://electrum-vips.info" - } - ] - }, - "bitcoin:VTC": { - "links": { - "Github": "https://github.com/vertcoin-project/vertcoin-core", - "Homepage": "https://vertcoin.org" - }, - "marketcap_usd": 10390580, - "name": "Vertcoin", - "shortcut": "VTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "bitcoin:XPM": { - "links": { - "Github": "https://github.com/primecoin/primecoin", - "Homepage": "https://primecoin.io" - }, - "marketcap_usd": 1320490, - "name": "Primecoin", - "shortcut": "XPM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-XPM", - "url": "https://github.com/justjamesdev/electrum-xpm" - } - ] - }, - "bitcoin:XRC": { - "links": { - "Github": "https://gitlab.com/bitcoinrh/BRhodiumNode", - "Homepage": "https://xrhodium.org" - }, - "marketcap_usd": 162003, - "name": "xRhodium", - "shortcut": "XRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-XRC", - "url": "https://electrum.xrhodium.org" - } - ] - }, - "bitcoin:XSN": { - "links": { - "Github": "https://github.com/X9Developers/XSN", - "Homepage": "https://stakenet.io" - }, - "marketcap_usd": 0, - "name": "Stakenet", - "shortcut": "XSN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Stakenet", - "url": "https://xsnexplorer.io/trezor" - } - ] - }, - "bitcoin:XVG": { - "links": { - "Github": "https://github.com/vergecurrency/VERGE", - "Homepage": "https://vergecurrency.com" - }, - "marketcap_usd": 55431549, - "name": "Verge", - "shortcut": "XVG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum", - "url": "https://github.com/vergecurrency/electrum/releases" - } - ] - }, - "bitcoin:ZCR": { - "links": { - "Github": "https://github.com/zcore-coin/zcore-2.0", - "Homepage": "https://zcore.cash" - }, - "marketcap_usd": 43805, - "name": "ZCore", - "shortcut": "ZCR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Electrum-ZCR", - "url": "https://github.com/zcore-coin/electrum-wallet/" - } - ] - }, - "bitcoin:ZEC": { - "links": { - "Github": "https://github.com/zcash/zcash", - "Homepage": "https://z.cash" - }, - "marketcap_usd": 719562172, - "name": "Zcash", - "shortcut": "ZEC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "erc20:avax:USDT": { - "address": "0xde3A24028580884448a5397872046a019649b084", - "links": { - "Homepage": "https://tether.to/" - }, - "marketcap_usd": 0, - "name": "Tether", - "network": "avax", - "shortcut": "USDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:avax:WAVAX": { - "address": "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7", - "links": { - "Github": "https://github.com/ava-labs", - "Homepage": "https://www.avalabs.org" - }, - "marketcap_usd": 0, - "name": "Avalanche", - "network": "avax", - "shortcut": "WAVAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:etc:UNV": { - "address": "0x6ADa6F48C815689502C43eC1a59F1b5DD3C04E1F", - "links": { - "Homepage": "https://universalcoin.io/" - }, - "marketcap_usd": 0, - "name": "UniversalCoin", - "network": "etc", - "shortcut": "UNV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:etc:UVC": { - "address": "0x76d0184CF511788032A74a1FB91146e63F43dd53", - "links": { - "Homepage": "https://universalcoin.io" - }, - "marketcap_usd": 0, - "name": "UniversalCoin", - "network": "etc", - "shortcut": "UVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:etc:UVCX": { - "address": "0xd6dF0C579f2A65049a893fDaEC9fCE098CC19F87", - "links": { - "Homepage": "https://universalcoin.io" - }, - "marketcap_usd": 0, - "name": "UniversalCoin X", - "network": "etc", - "shortcut": "UVCX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:$FFC": { - "address": "0x4E84E9e5fb0A972628Cf4568c403167EF1D40431", - "links": { - "Github": "https://github.com/Fluzcoin", - "Homepage": "https://fluzcoin.io/" - }, - "marketcap_usd": 0, - "name": "$Fluzcoin", - "network": "eth", - "shortcut": "$FFC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:$TEAK": { - "address": "0x7DD7F56D697Cc0f2b52bD55C057f378F1fE6Ab4b", - "links": { - "Homepage": "https://steak.network" - }, - "marketcap_usd": 0, - "name": "$TEAK", - "network": "eth", - "shortcut": "$TEAK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:00": { - "address": "0x881Ba05de1E78f549cC63a8f6Cabb1d4AD32250D", - "links": { - "Github": "https://github.com/p00ls/contracts", - "Homepage": "https://p00ls.io" - }, - "marketcap_usd": 0, - "name": "00 Token", - "network": "eth", - "shortcut": "00", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:0xBTC": { - "address": "0xB6eD7644C69416d67B522e20bC294A9a9B405B31", - "links": { - "Homepage": "https://0xbitcoin.org/" - }, - "marketcap_usd": 1723091, - "name": "0xBitcoin", - "network": "eth", - "shortcut": "0xBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:1SG": { - "address": "0x0F72714B35a366285Df85886A2eE174601292A17", - "links": { - "Github": "https://github.com/MarsBlockchain/1sg-contract", - "Homepage": "https://www.1.sg" - }, - "marketcap_usd": 0, - "name": "1SG", - "network": "eth", - "shortcut": "1SG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:1ST": { - "address": "0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7", - "links": { - "Homepage": "https://firstblood.io" - }, - "marketcap_usd": 0, - "name": "FirstBlood", - "network": "eth", - "shortcut": "1ST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:1WO": { - "address": "0xfDBc1aDc26F0F8f8606a5d63b7D3a3CD21c22B23", - "links": { - "Homepage": "https://ico.1worldonline.com" - }, - "marketcap_usd": 0, - "name": "1World", - "network": "eth", - "shortcut": "1WO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:300": { - "address": "0xaEc98A708810414878c3BCDF46Aad31dEd4a4557", - "links": { - "Homepage": "https://300tokensparta.com" - }, - "marketcap_usd": 0, - "name": "300 Token Sparta", - "network": "eth", - "shortcut": "300", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:3LT": { - "address": "0x430241368c1D293fdA21DBa8Bb7aF32007c59109", - "links": { - "Homepage": "https://3lt.io" - }, - "marketcap_usd": 0, - "name": "TrillionToken", - "network": "eth", - "shortcut": "3LT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:599GTO1": { - "address": "0x5D9776472483eE2c2B204775547BFf6db5A30Fed", - "links": { - "Github": "https://github.com/BitCar-io/cartokens", - "Homepage": "https://go.bitcar.io/599gto" - }, - "marketcap_usd": 0, - "name": "Ferrari 599 GTO 1", - "network": "eth", - "shortcut": "599GTO1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:A": { - "address": "0xFFc63b9146967A1ba33066fB057EE3722221aCf0", - "links": { - "Github": "https://github.com/crypt04dvisor/AlphaWallet", - "Homepage": "https://alphaplatform.co/" - }, - "marketcap_usd": 139356, - "name": "Alpha", - "network": "eth", - "shortcut": "A", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AAVE": { - "address": "0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9", - "links": { - "Github": "https://github.com/aave", - "Homepage": "https://aave.com/ " - }, - "marketcap_usd": 1111722344, - "name": "Aave", - "network": "eth", - "shortcut": "AAVE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ABCH": { - "address": "0xcc7d26D8eA6281BB363C8448515F2C61F7BC19F0", - "links": { - "Github": "https://github.com/ABBCCash/ABBCCashtoken", - "Homepage": "https://www.abbcfoundation.com/" - }, - "marketcap_usd": 0, - "name": "ABBC Cash", - "network": "eth", - "shortcut": "ABCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ABDX": { - "address": "0xB348cB0638b2399aE598b5575D5c12e0F15d3690", - "links": { - "Github": "https://github.com/allbandex", - "Homepage": "https://allbandex.net/" - }, - "marketcap_usd": 0, - "name": "allbandex", - "network": "eth", - "shortcut": "ABDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ABPT": { - "address": "0xcb03bec536843D338ac138205a6689d4cDc11046", - "links": { - "Github": "https://github.com/abptcrypto", - "Homepage": "http://abptcrypto.com" - }, - "marketcap_usd": 0, - "name": "ABPT Crypto", - "network": "eth", - "shortcut": "ABPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ABT": { - "address": "0xB98d4C97425d9908E66E53A6fDf673ACcA0BE986", - "links": { - "Homepage": "https://www.arcblock.io" - }, - "marketcap_usd": 14156469, - "name": "ArcBlock Token", - "network": "eth", - "shortcut": "ABT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ABYSS": { - "address": "0x0E8d6b471e332F140e7d9dbB99E5E3822F728DA6", - "links": { - "Github": "https://github.com/theabyssportal", - "Homepage": "https://www.theabyss.com" - }, - "marketcap_usd": 3473031, - "name": "Abyss Token", - "network": "eth", - "shortcut": "ABYSS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ACC": { - "address": "0x13F1b7FDFbE1fc66676D56483e21B1ecb40b58E2", - "links": { - "Homepage": "http://accelerator.network" - }, - "marketcap_usd": 0, - "name": "Accelerator Network", - "network": "eth", - "shortcut": "ACC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ACE": { - "address": "0x06147110022B768BA8F99A8f385df11a151A9cc8", - "links": { - "Homepage": "https://tokenstars.com/en/ace" - }, - "marketcap_usd": 0, - "name": "ACE (TokenStars)", - "network": "eth", - "shortcut": "ACE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADB": { - "address": "0x2baac9330Cf9aC479D819195794d79AD0c7616e3", - "links": { - "Homepage": "https://adbank.network" - }, - "marketcap_usd": 928468, - "name": "adbank", - "network": "eth", - "shortcut": "ADB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADC$": { - "address": "0x827Fe1736CEe36F7737Be6cF502434aF294Cf137", - "links": { - "Github": "https://github.com/africa-digital-coin-adc", - "Homepage": "http://africadigitalcoin.com" - }, - "marketcap_usd": 0, - "name": "Africa Digital Coin", - "network": "eth", - "shortcut": "ADC$", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADCO": { - "address": "0xB6c3DC857845a713d3531cea5ac546F6767992F4", - "links": { - "Github": "https://github.com/advertisecoin", - "Homepage": "https://advertisecoin.com" - }, - "marketcap_usd": 0, - "name": "Advertise Coin", - "network": "eth", - "shortcut": "ADCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADH": { - "address": "0xE69a353b3152Dd7b706ff7dD40fe1d18b7802d31", - "links": { - "Homepage": "https://adhive.tv" - }, - "marketcap_usd": 0, - "name": "AdHive Token", - "network": "eth", - "shortcut": "ADH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADI": { - "address": "0x8810C63470d38639954c6B41AaC545848C46484a", - "links": { - "Github": "https://github.com/aditus", - "Homepage": "https://aditus.net" - }, - "marketcap_usd": 52124, - "name": "Aditus", - "network": "eth", - "shortcut": "ADI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADL": { - "address": "0x660e71483785f66133548B10f6926dC332b06e61", - "links": { - "Github": "https://github.com/adelecosystem", - "Homepage": "https://adel.io" - }, - "marketcap_usd": 0, - "name": "Adelphoi", - "network": "eth", - "shortcut": "ADL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADST": { - "address": "0x422866a8F0b032c5cf1DfBDEf31A20F4509562b0", - "links": { - "Homepage": "https://adshares.net" - }, - "marketcap_usd": 0, - "name": "AdShares", - "network": "eth", - "shortcut": "ADST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADT": { - "address": "0xD0D6D6C5Fe4a677D343cC433536BB717bAe167dD", - "links": { - "Github": "https://github.com/adchain", - "Homepage": "https://adtoken.com" - }, - "marketcap_usd": 0, - "name": "AdToken", - "network": "eth", - "shortcut": "ADT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ADX-LOYALTY": { - "address": "0xd9A4cB9dc9296e111c66dFACAb8Be034EE2E1c2C", - "links": { - "Github": "https://github.com/AdExNetwork", - "Homepage": "https://www.adex.network" - }, - "marketcap_usd": 0, - "name": "AdEx Loyalty", - "network": "eth", - "shortcut": "ADX-LOYALTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AE": { - "address": "0x5CA9a71B1d01849C0a95490Cc00559717fCF0D1d", - "links": { - "Github": "https://github.com/aeternity", - "Homepage": "https://www.aeternity.com/" - }, - "marketcap_usd": 0, - "name": "aeternity", - "network": "eth", - "shortcut": "AE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AEUR": { - "address": "0xc994a2dEb02543Db1f48688438b9903c4b305ce3", - "links": { - "Github": "https://github.com/Augmint", - "Homepage": "https://www.augmint.org" - }, - "marketcap_usd": 0, - "name": "Augmint Euro", - "network": "eth", - "shortcut": "AEUR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AFA": { - "address": "0xfB48E0DEa837f9438309a7e9F0cFe7EE3353A84e", - "links": { - "Github": "https://github.com/mdpienaar/ipparts", - "Homepage": "https://www.africahead.co.za" - }, - "marketcap_usd": 0, - "name": "Africahead Ipparts", - "network": "eth", - "shortcut": "AFA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AGI": { - "address": "0x8eB24319393716668D768dCEC29356ae9CfFe285", - "links": { - "Github": "https://github.com/singnet/singnet", - "Homepage": "https://singularitynet.io" - }, - "marketcap_usd": 0, - "name": "SingularityNET", - "network": "eth", - "shortcut": "AGI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AGRS": { - "address": "0x738865301A9b7Dd80Dc3666dD48cF034ec42bdDa", - "links": { - "Github": "https://github.com/IDNI", - "Homepage": "https://tau.net/" - }, - "marketcap_usd": 6463799, - "name": "Agoras: Currency of Tau", - "network": "eth", - "shortcut": "AGRS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AGS": { - "address": "0x7db5454F3500f28171d1f9c7a38527C9cF94e6b2", - "links": { - "Github": "https://github.com/GoldSilverStandard", - "Homepage": "https://www.goldsilverstandard.com/" - }, - "marketcap_usd": 0, - "name": "Silver Standard", - "network": "eth", - "shortcut": "AGS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AI": { - "address": "0x5121E348e897dAEf1Eef23959Ab290e5557CF274", - "links": { - "Homepage": "https://polynetwork.org" - }, - "marketcap_usd": 0, - "name": "POLY AI", - "network": "eth", - "shortcut": "AI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AID": { - "address": "0x37E8789bB9996CaC9156cD5F5Fd32599E6b91289", - "links": { - "Homepage": "https://www.aidcoin.co" - }, - "marketcap_usd": 296328, - "name": "AidCoin", - "network": "eth", - "shortcut": "AID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AION": { - "address": "0x4CEdA7906a5Ed2179785Cd3A40A69ee8bc99C466", - "links": { - "Github": "https://github.com/aionnetwork", - "Homepage": "https://aion.network/" - }, - "marketcap_usd": 0, - "name": "Aion", - "network": "eth", - "shortcut": "AION", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AIR": { - "address": "0x27Dce1eC4d3f72C3E457Cc50354f1F975dDEf488", - "links": { - "Homepage": "https://airtoken.com" - }, - "marketcap_usd": 0, - "name": "AirToken", - "network": "eth", - "shortcut": "AIR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AIX": { - "address": "0x1063ce524265d5a3A624f4914acd573dD89ce988", - "links": { - "Github": "https://github.com/AigangNetwork", - "Homepage": "https://aigang.network/" - }, - "marketcap_usd": 2866, - "name": "Aigang", - "network": "eth", - "shortcut": "AIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AKC": { - "address": "0x1Ca43a170BaD619322e6f54d46b57e504dB663aA", - "links": { - "Github": "https://github.com/artwook", - "Homepage": "https://artwook.com" - }, - "marketcap_usd": 0, - "name": "ARTWOOK COIN", - "network": "eth", - "shortcut": "AKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALCO": { - "address": "0x181a63746d3Adcf356CBc73aCE22832FFBB1EE5A", - "links": { - "Homepage": "https://alaricoin.org" - }, - "marketcap_usd": 0, - "name": "ALCO", - "network": "eth", - "shortcut": "ALCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALEPH": { - "address": "0x27702a26126e0B3702af63Ee09aC4d1A084EF628", - "links": { - "Github": "https://github.com/aleph-im/", - "Homepage": "https://aleph.im" - }, - "marketcap_usd": 17910289, - "name": "Aleph.im", - "network": "eth", - "shortcut": "ALEPH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALI": { - "address": "0x4289c043A12392F1027307fB58272D8EBd853912", - "links": { - "Homepage": "http://ailink.in" - }, - "marketcap_usd": 0, - "name": "AiLink Token", - "network": "eth", - "shortcut": "ALI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALIS": { - "address": "0xEA610B1153477720748DC13ED378003941d84fAB", - "links": { - "Github": "https://github.com/AlisProject", - "Homepage": "https://alismedia.jp" - }, - "marketcap_usd": 0, - "name": "ALIS Token", - "network": "eth", - "shortcut": "ALIS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALTA": { - "address": "0xe0cCa86B254005889aC3a81e737f56a14f4A38F5", - "links": { - "Github": "https://github.com/altafinprotocol", - "Homepage": "https://alta.finance" - }, - "marketcap_usd": 0, - "name": "Alta Finance", - "network": "eth", - "shortcut": "ALTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALTS": { - "address": "0x638AC149eA8EF9a1286C41B977017AA7359E6Cfa", - "links": { - "Homepage": "http://www.altcoinstalks.com" - }, - "marketcap_usd": 0, - "name": "ALTS Token", - "network": "eth", - "shortcut": "ALTS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ALX": { - "address": "0x49b127Bc33ce7E1586EC28CEC6a65b112596C822", - "links": { - "Homepage": "https://alax.io" - }, - "marketcap_usd": 0, - "name": "ALAX", - "network": "eth", - "shortcut": "ALX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMB": { - "address": "0x4DC3643DbC642b72C158E7F3d2ff232df61cb6CE", - "links": { - "Github": "https://github.com/ambrosus", - "Homepage": "https://ambrosus.com/index.html" - }, - "marketcap_usd": 0, - "name": "Amber Token", - "network": "eth", - "shortcut": "AMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMGO": { - "address": "0xf1aC7A375429719DE0dde33528e2639B9a206ebA", - "links": { - "Github": "https://github.com/arenamatch", - "Homepage": "https://arenamatch.com/amg" - }, - "marketcap_usd": 0, - "name": "Arena Match Gold", - "network": "eth", - "shortcut": "AMGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMIS": { - "address": "0x949bEd886c739f1A3273629b3320db0C5024c719", - "links": { - "Github": "https://github.com/amisolution/ERC20-AMIS", - "Homepage": "http://erc20-amis.amisolution.net" - }, - "marketcap_usd": 0, - "name": "AMIS", - "network": "eth", - "shortcut": "AMIS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMLT": { - "address": "0xCA0e7269600d353F70b14Ad118A49575455C0f2f", - "links": { - "Github": "https://github.com/amlt-by-coinfirm", - "Homepage": "https://amlt.coinfirm.io/" - }, - "marketcap_usd": 1874483, - "name": "AMLT", - "network": "eth", - "shortcut": "AMLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMN": { - "address": "0x737F98AC8cA59f2C68aD658E3C3d8C8963E40a4c", - "links": { - "Github": "https://github.com/amontech", - "Homepage": "https://amon.tech" - }, - "marketcap_usd": 227037, - "name": "Amon", - "network": "eth", - "shortcut": "AMN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMO": { - "address": "0x38c87AA89B2B8cD9B95b736e1Fa7b612EA972169", - "links": { - "Github": "https://github.com/AMO-Project/", - "Homepage": "https://amo.foundation" - }, - "marketcap_usd": 15060121, - "name": "AMO Coin", - "network": "eth", - "shortcut": "AMO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMON": { - "address": "0x00059AE69c1622A7542EdC15E8d17b060fE307b6", - "links": { - "Homepage": "https://ados.foundation/" - }, - "marketcap_usd": 709645, - "name": "Token AmonD", - "network": "eth", - "shortcut": "AMON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMP": { - "address": "0xfF20817765cB7f73d4bde2e66e067E58D11095C2", - "links": { - "Github": "https://github.com/amptoken", - "Homepage": "https://amptoken.org" - }, - "marketcap_usd": 238924137, - "name": "Amp", - "network": "eth", - "shortcut": "AMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMPL": { - "address": "0xD46bA6D942050d489DBd938a2C909A5d5039A161", - "links": { - "Github": "https://github.com/ampleforth", - "Homepage": "https://ampleforth.org" - }, - "marketcap_usd": 46578948, - "name": "Ampleforth", - "network": "eth", - "shortcut": "AMPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AMTC": { - "address": "0x84936cF7630AA3e27Dd9AfF968b140d5AEE49F5a", - "links": { - "Homepage": "https://ambertime.org/" - }, - "marketcap_usd": 0, - "name": "AmberTime Coin", - "network": "eth", - "shortcut": "AMTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ANIME": { - "address": "0xc36e2C02e64585c15794B8e25E826d50b15fd878", - "links": { - "Github": "https://github.com/Animeyen", - "Homepage": "https://animeyen.com" - }, - "marketcap_usd": 0, - "name": "Animeyen", - "network": "eth", - "shortcut": "ANIME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ANJ": { - "address": "0xcD62b1C403fa761BAadFC74C525ce2B51780b184", - "links": { - "Github": "https://github.com/aragon/aragon-court", - "Homepage": "https://anj.aragon.org/" - }, - "marketcap_usd": 0, - "name": "Aragon Network Juror", - "network": "eth", - "shortcut": "ANJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AOA": { - "address": "0x9ab165D795019b6d8B3e971DdA91071421305e5a", - "links": { - "Homepage": "https://www.aurorachain.io" - }, - "marketcap_usd": 2078947, - "name": "Aurora", - "network": "eth", - "shortcut": "AOA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:API3": { - "address": "0x0b38210ea11411557c13457D4dA7dC6ea731B88a", - "links": { - "Github": "https://github.com/api3dao", - "Homepage": "https://api3.org/" - }, - "marketcap_usd": 124100419, - "name": "API3", - "network": "eth", - "shortcut": "API3", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:APIS": { - "address": "0x4C0fBE1BB46612915E7967d2C3213cd4d87257AD", - "links": { - "Github": "https://github.com/Oxchild/crowdsale", - "Homepage": "https://apisplatform.io" - }, - "marketcap_usd": 0, - "name": "APIS", - "network": "eth", - "shortcut": "APIS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:APPC": { - "address": "0x1a7a8BD9106F2B8D977E08582DC7d24c723ab0DB", - "links": { - "Github": "https://github.com/Aptoide/AppCoins-ethereumj", - "Homepage": "https://appcoins.io" - }, - "marketcap_usd": 0, - "name": "AppCoins", - "network": "eth", - "shortcut": "APPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:APT": { - "address": "0x23aE3C5B39B12f0693e05435EeaA1e51d8c61530", - "links": { - "Homepage": "https://aigang.network" - }, - "marketcap_usd": 0, - "name": "AIGang", - "network": "eth", - "shortcut": "APT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AQT": { - "address": "0x2a9bDCFF37aB68B95A53435ADFd8892e86084F93", - "links": { - "Github": "https://github.com/alphaquark/Alpha-Quark", - "Homepage": "https://www.alphaquark.io" - }, - "marketcap_usd": 33804550, - "name": "AlphaQuarkToken", - "network": "eth", - "shortcut": "AQT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARC": { - "address": "0xAc709FcB44a43c35F0DA4e3163b117A17F3770f5", - "links": { - "Github": "https://github.com/swarmcity/ac-token", - "Homepage": "https://arcade.city" - }, - "marketcap_usd": 0, - "name": "Arcade Token", - "network": "eth", - "shortcut": "ARC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARCT": { - "address": "0x1245ef80F4d9e02ED9425375e8F649B9221b31D8", - "links": { - "Homepage": "https://www.arbitragect.com" - }, - "marketcap_usd": 48931, - "name": "ArbitrageCT", - "network": "eth", - "shortcut": "ARCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARD": { - "address": "0x75Aa7B0d02532f3833b66c7f0Ad35376d373ddF8", - "links": { - "Github": "https://github.com/accordtoken", - "Homepage": "https://accordtoken.com" - }, - "marketcap_usd": 0, - "name": "Accord", - "network": "eth", - "shortcut": "ARD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARE": { - "address": "0x92afBa413BF9E5DA3919A522E371884bEAC76309", - "links": { - "Github": "https://github.com/AureiProject/aurei-token", - "Homepage": "https://www.aurei-crypto.io/" - }, - "marketcap_usd": 0, - "name": "Aurei", - "network": "eth", - "shortcut": "ARE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARN": { - "address": "0xBA5F11b16B155792Cf3B2E6880E8706859A8AEB6", - "links": { - "Homepage": "https://aeron.aero" - }, - "marketcap_usd": 0, - "name": "Aeron", - "network": "eth", - "shortcut": "ARN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARNX": { - "address": "0x0C37Bcf456bC661C14D596683325623076D7e283", - "links": { - "Github": "https://github.com/aeronaero/aeron", - "Homepage": "https://aeron.aero" - }, - "marketcap_usd": 95, - "name": "Aeron", - "network": "eth", - "shortcut": "ARNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ART": { - "address": "0xfec0cF7fE078a500abf15F1284958F22049c2C7e", - "links": { - "Homepage": "http://www.maecenas.co" - }, - "marketcap_usd": 41649, - "name": "Maecenas", - "network": "eth", - "shortcut": "ART", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARX": { - "address": "0x7705FaA34B16EB6d77Dfc7812be2367ba6B0248e", - "links": { - "Github": "https://github.com/va109/Artex", - "Homepage": "https://artex.global" - }, - "marketcap_usd": 0, - "name": "ARX", - "network": "eth", - "shortcut": "ARX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARXT": { - "address": "0xb0D926c1BC3d78064F3e1075D5bD9A24F35Ae6C5", - "links": { - "Github": "https://github.com/va109/Artex", - "Homepage": "https://aronline.io" - }, - "marketcap_usd": 0, - "name": "Assistive Reality ARX", - "network": "eth", - "shortcut": "ARXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ARY": { - "address": "0xa5F8fC0921880Cb7342368BD128eb8050442B1a1", - "links": { - "Homepage": "https://www.blockarray.com" - }, - "marketcap_usd": 0, - "name": "Block Array", - "network": "eth", - "shortcut": "ARY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AST": { - "address": "0x27054b13b1B798B345b591a4d22e6562d47eA75a", - "links": { - "Homepage": "https://airswap.io" - }, - "marketcap_usd": 19734634, - "name": "Airswap", - "network": "eth", - "shortcut": "AST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ASY": { - "address": "0x017B584AcFD16D767541aE9e80cdc702F4527B0b", - "links": { - "Github": "https://github.com/Asyagro/ASY", - "Homepage": "https://asyagro.io" - }, - "marketcap_usd": 0, - "name": "ASYAGRO", - "network": "eth", - "shortcut": "ASY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATL": { - "address": "0x78B7FADA55A64dD895D8c8c35779DD8b67fA8a05", - "links": { - "Homepage": "https://atlant.io" - }, - "marketcap_usd": 638027, - "name": "ATLANT", - "network": "eth", - "shortcut": "ATL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATM": { - "address": "0x9B11EFcAAA1890f6eE52C6bB7CF8153aC5d74139", - "links": { - "Homepage": "https://www.atmchain.io" - }, - "marketcap_usd": 0, - "name": "ATMChain", - "network": "eth", - "shortcut": "ATM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATMI": { - "address": "0x97AEB5066E1A590e868b511457BEb6FE99d329F5", - "links": { - "Github": "https://github.com/atonomi", - "Homepage": "https://atonomi.io" - }, - "marketcap_usd": 0, - "name": "Atonomi", - "network": "eth", - "shortcut": "ATMI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATT": { - "address": "0x887834D3b8D450B6bAB109c252Df3DA286d73CE4", - "links": { - "Github": "https://github.com/ATMatrix", - "Homepage": "https://atmatrix.org/?locale=en" - }, - "marketcap_usd": 0, - "name": "Atmatrix Token", - "network": "eth", - "shortcut": "ATT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATTN": { - "address": "0x6339784d9478dA43106A429196772A029C2f177d", - "links": { - "Homepage": "https://attentionnetwork.io" - }, - "marketcap_usd": 0, - "name": "Attention Token", - "network": "eth", - "shortcut": "ATTN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ATX": { - "address": "0x1A0F2aB46EC630F9FD638029027b552aFA64b94c", - "links": { - "Homepage": "https://www.aston.company" - }, - "marketcap_usd": 0, - "name": "Aston", - "network": "eth", - "shortcut": "ATX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AUC": { - "address": "0xc12d099be31567add4e4e4d0D45691C3F58f5663", - "links": { - "Homepage": "https://auctus.org" - }, - "marketcap_usd": 141310, - "name": "Auctus", - "network": "eth", - "shortcut": "AUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AUDIO": { - "address": "0x18aAA7115705e8be94bfFEBDE57Af9BFc265B998", - "links": { - "Github": "https://github.com/audiusproject", - "Homepage": "https://audius.co" - }, - "marketcap_usd": 323841415, - "name": "Audius", - "network": "eth", - "shortcut": "AUDIO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AURA": { - "address": "0xCdCFc0f66c522Fd086A1b725ea3c0Eeb9F9e8814", - "links": { - "Homepage": "https://auroradao.com" - }, - "marketcap_usd": 0, - "name": "Aurora DAO", - "network": "eth", - "shortcut": "AURA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AUS": { - "address": "0x5FB9E9C359CC7191b0293d2FAF1cC41cE3688D75", - "links": { - "Github": "https://github.com/GoldSilverStandard", - "Homepage": "https://www.goldsilverstandard.com/" - }, - "marketcap_usd": 0, - "name": "Gold Standard", - "network": "eth", - "shortcut": "AUS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AUTO": { - "address": "0x622dFfCc4e83C64ba959530A5a5580687a57581b", - "links": { - "Homepage": "https://cubeint.io" - }, - "marketcap_usd": 0, - "name": "Cube", - "network": "eth", - "shortcut": "AUTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AVA": { - "address": "0xeD247980396B10169BB1d36f6e278eD16700a60f", - "links": { - "Github": "https://github.com/AvalonPlatform", - "Homepage": "https://avalon.nu" - }, - "marketcap_usd": 0, - "name": "AVA", - "network": "eth", - "shortcut": "AVA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AVT": { - "address": "0x0d88eD6E74bbFD96B831231638b66C05571e824F", - "links": { - "Homepage": "https://aventus.io" - }, - "marketcap_usd": 7052932, - "name": "Aventus", - "network": "eth", - "shortcut": "AVT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AX1": { - "address": "0xCd4b4b0F3284a33AC49C67961EC6e111708318Cf", - "links": { - "Github": "https://github.com/Pickeringwareltd/AX1_v1.03", - "Homepage": "https://ax1.io" - }, - "marketcap_usd": 0, - "name": "AX1 Mining Token", - "network": "eth", - "shortcut": "AX1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AXN": { - "address": "0x71F85B2E46976bD21302B64329868fd15eb0D127", - "links": { - "Github": "https://github.com/Axion-Network", - "Homepage": "https://axion.network/" - }, - "marketcap_usd": 0, - "name": "Axion", - "network": "eth", - "shortcut": "AXN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AXP": { - "address": "0x9af2c6B1A28D3d6BC084bd267F70e90d49741D5B", - "links": { - "Homepage": "https://www.axpire.io/" - }, - "marketcap_usd": 0, - "name": "AXP", - "network": "eth", - "shortcut": "AXP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AXPR": { - "address": "0xC39E626A04C5971D770e319760D7926502975e47", - "links": { - "Github": "https://www.github.com/axpire", - "Homepage": "https://www.axpire.io" - }, - "marketcap_usd": 0, - "name": "aXpire", - "network": "eth", - "shortcut": "AXPR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:AXS": { - "address": "0xBB0E17EF65F82Ab018d8EDd776e8DD940327B28b", - "links": { - "Github": "https://github.com/axieinfinity", - "Homepage": "https://axieinfinity.com/" - }, - "marketcap_usd": 1098056194, - "name": "Axie Infinity Shards", - "network": "eth", - "shortcut": "AXS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:B2BX": { - "address": "0x5d51FCceD3114A8bb5E90cDD0f9d682bCbCC5393", - "links": { - "Homepage": "https://www.b2bx.exchange" - }, - "marketcap_usd": 0, - "name": "B2BX", - "network": "eth", - "shortcut": "B2BX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAC": { - "address": "0x062e3Be6a7C56A395b1881A0cD69A4923Ade4fa2", - "links": { - "Github": "https://github.com/bowlacoin", - "Homepage": "https://bowlacoin.com" - }, - "marketcap_usd": 0, - "name": "Bowl A Coin", - "network": "eth", - "shortcut": "BAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAL": { - "address": "0xba100000625a3754423978a60c9317c58a424e3D", - "links": { - "Github": "https://github.com/balancer-labs", - "Homepage": "https://balancer.finance" - }, - "marketcap_usd": 329982207, - "name": "Balancer", - "network": "eth", - "shortcut": "BAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BALI": { - "address": "0x013A06558f07d9E6F9A00c95a33f3a0E0255176b", - "links": { - "Github": "https://github.com/adamyusfan/balicoin", - "Homepage": "https://balicoin.io/" - }, - "marketcap_usd": 0, - "name": "BALI COIN", - "network": "eth", - "shortcut": "BALI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAMBOO": { - "address": "0xf56842Af3B56Fd72d17cB103f92d027bBa912e89", - "links": { - "Github": "https://github.com/bamboo-defi", - "Homepage": "https://www.bamboodefi.com/" - }, - "marketcap_usd": 0, - "name": "BambooDeFi", - "network": "eth", - "shortcut": "BAMBOO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BANCA": { - "address": "0x998b3B82bC9dBA173990Be7afb772788B5aCB8Bd", - "links": { - "Homepage": "https://www.banca.world" - }, - "marketcap_usd": 152329, - "name": "Banca", - "network": "eth", - "shortcut": "BANCA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BANX": { - "address": "0xF87F0D9153fea549c728Ad61cb801595a68b73de", - "links": { - "Homepage": "https://pre.ubanx.io" - }, - "marketcap_usd": 0, - "name": "BANX", - "network": "eth", - "shortcut": "BANX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAR": { - "address": "0xc73f2474001aD1D6aEd615aF53631148CF98dE6b", - "links": { - "Github": "https://github.com/BillonareAmbitionToken", - "Homepage": "http://billionareambition.com" - }, - "marketcap_usd": 0, - "name": "Billionaire Ambition", - "network": "eth", - "shortcut": "BAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAT": { - "address": "0x0D8775F648430679A709E98d2b0Cb6250d2887EF", - "links": { - "Homepage": "https://basicattentiontoken.org" - }, - "marketcap_usd": 442713735, - "name": "Basic Attention Token", - "network": "eth", - "shortcut": "BAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BAX": { - "address": "0x9a0242b7a33DAcbe40eDb927834F96eB39f8fBCB", - "links": { - "Homepage": "https://getbabb.com" - }, - "marketcap_usd": 0, - "name": "BABB", - "network": "eth", - "shortcut": "BAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BBC": { - "address": "0xe7D3e4413E29ae35B0893140F4500965c74365e5", - "links": { - "Homepage": "http://bbcoin.tradove.com" - }, - "marketcap_usd": 0, - "name": "TraDove B2BCoin", - "network": "eth", - "shortcut": "BBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BBK": { - "address": "0x4a6058666cf1057eaC3CD3A5a614620547559fc9", - "links": { - "Github": "https://github.com/brickblock-io", - "Homepage": "https://www.brickblock.io/" - }, - "marketcap_usd": 0, - "name": "BRICKBLOCK TOKEN", - "network": "eth", - "shortcut": "BBK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BBN": { - "address": "0x35a69642857083BA2F30bfaB735dacC7F0bac969", - "links": { - "Homepage": "http://www.banyanbbt.org" - }, - "marketcap_usd": 0, - "name": "Banyan Network", - "network": "eth", - "shortcut": "BBN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BBO": { - "address": "0x84F7c44B6Fed1080f647E354D552595be2Cc602F", - "links": { - "Homepage": "https://bigbom.com" - }, - "marketcap_usd": 0, - "name": "Bigbom", - "network": "eth", - "shortcut": "BBO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BC": { - "address": "0x2ecB13A8c458c379c4d9a7259e202De03c8F3D19", - "links": { - "Homepage": "https://block-chain.com" - }, - "marketcap_usd": 0, - "name": "Block-Chain.com", - "network": "eth", - "shortcut": "BC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCASH": { - "address": "0xb5BB48567BfD0bFE9e4B08EF8b7f91556CC2a112", - "links": { - "Homepage": "https://bankcoinbcash.com" - }, - "marketcap_usd": 0, - "name": "Bankcoin", - "network": "eth", - "shortcut": "BCASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCBC": { - "address": "0x7367A68039d4704f30BfBF6d948020C3B07DFC59", - "links": { - "Github": "https://github.com/beerchain/beercoin", - "Homepage": "https://www.beerchain.technology" - }, - "marketcap_usd": 0, - "name": "Beercoin", - "network": "eth", - "shortcut": "BCBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCDN": { - "address": "0x1e797Ce986C3CFF4472F7D38d5C4aba55DfEFE40", - "links": { - "Github": "https://github.com/Blockcdnteam", - "Homepage": "https://www.blockcdn.org" - }, - "marketcap_usd": 0, - "name": "BlockCDN", - "network": "eth", - "shortcut": "BCDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCDT": { - "address": "0xAcfa209Fb73bF3Dd5bBfb1101B9Bc999C49062a5", - "links": { - "Github": "https://github.com/VinceBCD/BCDiploma", - "Homepage": "https://www.bcdiploma.com" - }, - "marketcap_usd": 2474009, - "name": "Blockchain Certified Data Token", - "network": "eth", - "shortcut": "BCDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCL": { - "address": "0xbc1234552EBea32B5121190356bBa6D3Bb225bb5", - "links": { - "Homepage": "https://www.bitclave.com" - }, - "marketcap_usd": 0, - "name": "BCL", - "network": "eth", - "shortcut": "BCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCMC1": { - "address": "0xD5e2A54Fef5f9E4A6b21EC646Bbed7A160a00F18", - "links": { - "Homepage": "https://beforecoinmarketcap.com/" - }, - "marketcap_usd": 0, - "name": "BeforeCoinMarketCap", - "network": "eth", - "shortcut": "BCMC1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCPT": { - "address": "0x1c4481750daa5Ff521A2a7490d9981eD46465Dbd", - "links": { - "Github": "https://github.com/blockmason", - "Homepage": "https://blockmason.io" - }, - "marketcap_usd": 285234, - "name": "BlockMason Credit Protocol Token", - "network": "eth", - "shortcut": "BCPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BCV": { - "address": "0x1014613E2B3CBc4d575054D4982E580d9b99d7B1", - "links": { - "Github": "https://github.com/bitcv", - "Homepage": "https://bitcv.one/" - }, - "marketcap_usd": 0, - "name": "BitCapitalVendor Token", - "network": "eth", - "shortcut": "BCV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BDG": { - "address": "0x1961B3331969eD52770751fC718ef530838b6dEE", - "links": { - "Github": "https://github.com/bitdegree", - "Homepage": "https://bitdegree.org" - }, - "marketcap_usd": 0, - "name": "BitDegree Token", - "network": "eth", - "shortcut": "BDG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BEAR": { - "address": "0x016ee7373248a80BDe1fD6bAA001311d233b3CFa", - "links": { - "Homepage": "https://ftx.com/tokens/BEAR" - }, - "marketcap_usd": 0, - "name": "3X Short Bitcoin Token", - "network": "eth", - "shortcut": "BEAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BEE": { - "address": "0x4D8fc1453a0F359e99c9675954e656D80d996FbF", - "links": { - "Github": "https://github.com/thebeetoken", - "Homepage": "https://www.beetoken.com" - }, - "marketcap_usd": 0, - "name": "Bee Token", - "network": "eth", - "shortcut": "BEE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BEFX": { - "address": "0xB91C2a2b953D72f3EF890490669a0A41B0ADD5f7", - "links": { - "Github": "https://github.com/Belifex", - "Homepage": "https://belifex.com/" - }, - "marketcap_usd": 0, - "name": "Belifex", - "network": "eth", - "shortcut": "BEFX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BERRY": { - "address": "0x6aEB95F06CDA84cA345c2dE0F3B7f96923a44f4c", - "links": { - "Github": "https://github.com/Rentberry", - "Homepage": "https://rentberry.com" - }, - "marketcap_usd": 107070, - "name": "Berry", - "network": "eth", - "shortcut": "BERRY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BET": { - "address": "0x8aA33A7899FCC8eA5fBe6A608A109c3893A1B8b2", - "links": { - "Github": "https://github.com/daocasino", - "Homepage": "https://dao.casino" - }, - "marketcap_usd": 0, - "name": "DAO.Casino", - "network": "eth", - "shortcut": "BET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BETHER": { - "address": "0x14C926F2290044B647e1Bf2072e67B495eff1905", - "links": { - "Github": "https://github.com/bethereumproject", - "Homepage": "https://www.bethereum.com/" - }, - "marketcap_usd": 0, - "name": "Bethereum", - "network": "eth", - "shortcut": "BETHER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BETR": { - "address": "0x763186eB8d4856D536eD4478302971214FEbc6A9", - "links": { - "Github": "https://github.com/betterbetting", - "Homepage": "https://www.betterbetting.org" - }, - "marketcap_usd": 0, - "name": "BetterBetting", - "network": "eth", - "shortcut": "BETR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BEZ": { - "address": "0x3839d8ba312751Aa0248fEd6a8bACB84308E20Ed", - "links": { - "Homepage": "https://bezop.io" - }, - "marketcap_usd": 0, - "name": "Bezop", - "network": "eth", - "shortcut": "BEZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BFT": { - "address": "0x01fF50f8b7f74E4f00580d9596cd3D0d6d6E326f", - "links": { - "Homepage": "https://bnktothefuture.com" - }, - "marketcap_usd": 3387108, - "name": "BnkToTheFuture", - "network": "eth", - "shortcut": "BFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BHPC": { - "address": "0xEE74110fB5A1007b06282e0DE5d73A61bf41d9Cd", - "links": { - "Homepage": "https://bhpcash.io/bhpc/index.html" - }, - "marketcap_usd": 0, - "name": "BHPCash", - "network": "eth", - "shortcut": "BHPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BHR": { - "address": "0xfe5D908c9Ad85f651185dAa6a4770726E2b27d09", - "links": { - "Homepage": "https://www.bether.cc" - }, - "marketcap_usd": 0, - "name": "BETHER", - "network": "eth", - "shortcut": "BHR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BID": { - "address": "0x25e1474170c4c0aA64fa98123bdc8dB49D7802fa", - "links": { - "Homepage": "https://bidaochain.com/" - }, - "marketcap_usd": 0, - "name": "Bidao", - "network": "eth", - "shortcut": "BID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BIT": { - "address": "0x089B85FA15f72c1088CBbef23a49DB80B91DD521", - "links": { - "Homepage": "https://www.blockestate.net" - }, - "marketcap_usd": 0, - "name": "BlockEstate Investment Token", - "network": "eth", - "shortcut": "BIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BITCAR": { - "address": "0x08b4c866aE9D1bE56a06e0C302054B4FFe067b43", - "links": { - "Github": "https://github.com/BitCar-io/BitCarToken", - "Homepage": "https://bitcar.io/" - }, - "marketcap_usd": 0, - "name": "BitCar Token", - "network": "eth", - "shortcut": "BITCAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BITX": { - "address": "0xff2b3353c3015E9f1FBF95B9Bda23F58Aa7cE007", - "links": { - "Github": "https://github.com/BitScreenerTech", - "Homepage": "https://tokensale.bitscreener.com/" - }, - "marketcap_usd": 0, - "name": "Token BitScreenerToken", - "network": "eth", - "shortcut": "BITX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BIX": { - "address": "0xb3104b4B9Da82025E8b9F8Fb28b3553ce2f67069", - "links": { - "Homepage": "https://www.bibox.com" - }, - "marketcap_usd": 0, - "name": "Bibox Token", - "network": "eth", - "shortcut": "BIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BKC": { - "address": "0xc88Be04c809856B75E3DfE19eB4dCf0a3B15317a", - "links": { - "Homepage": "https://bankcoin-cash.com/" - }, - "marketcap_usd": 0, - "name": "Bankcoin Cash", - "network": "eth", - "shortcut": "BKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BKN": { - "address": "0xBeE6EDF5fa7e862ed2eA9b9f42cb0849184aAE85", - "links": { - "Github": "https://github.com/blockstatecom", - "Homepage": "https://blockstate.com" - }, - "marketcap_usd": 0, - "name": "BlockState Security Token", - "network": "eth", - "shortcut": "BKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BKRx": { - "address": "0x3cf9E0c385a5ABEC9FD2a71790AA344C4e8E3570", - "links": { - "Homepage": "https://www.blockrx.com" - }, - "marketcap_usd": 0, - "name": "BlockRx", - "network": "eth", - "shortcut": "BKRx", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BKX": { - "address": "0x45245bc59219eeaAF6cD3f382e078A461FF9De7B", - "links": { - "Github": "https://github.com/BankEx", - "Homepage": "https://bankex.com/" - }, - "marketcap_usd": 0, - "name": "BANKEX", - "network": "eth", - "shortcut": "BKX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLN": { - "address": "0xCA29db4221c111888a7e80b12eAc8a266Da3Ee0d", - "links": { - "Homepage": "http://bolenum.com" - }, - "marketcap_usd": 0, - "name": "Bolenum", - "network": "eth", - "shortcut": "BLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLO": { - "address": "0x1C3BB10dE15C31D5DBE48fbB7B87735d1B7d8c32", - "links": { - "Github": "https://github.com/blondcoin", - "Homepage": "http://blondcoin.com" - }, - "marketcap_usd": 0, - "name": "BLONDCOIN", - "network": "eth", - "shortcut": "BLO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLT": { - "address": "0x107c4504cd79C5d2696Ea0030a8dD4e92601B82e", - "links": { - "Github": "https://github.com/hellobloom", - "Homepage": "https://hellobloom.io" - }, - "marketcap_usd": 3006871, - "name": "Bloom", - "network": "eth", - "shortcut": "BLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLUE": { - "address": "0x539EfE69bCDd21a83eFD9122571a64CC25e0282b", - "links": { - "Github": "https://github.com/BlueCrypto", - "Homepage": "https://blueprotocol.com/" - }, - "marketcap_usd": 234732, - "name": "Ethereum Blue", - "network": "eth", - "shortcut": "BLUE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLX (Bullion)": { - "address": "0xcE59d29b09aAE565fEEEf8E52f47c3CD5368C663", - "links": { - "Github": "https://github.com/bullioncoin", - "Homepage": "http://www.bullioncrypto.info" - }, - "marketcap_usd": 0, - "name": "Bullion Crypto", - "network": "eth", - "shortcut": "BLX (Bullion)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLX (Iconomi)": { - "address": "0xE5a7c12972f3bbFe70ed29521C8949b8Af6a0970", - "links": { - "Homepage": "https://www.iconomi.net" - }, - "marketcap_usd": 0, - "name": "Iconomi", - "network": "eth", - "shortcut": "BLX (Iconomi)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BLZ": { - "address": "0x5732046A883704404F284Ce41FfADd5b007FD668", - "links": { - "Homepage": "https://bluzelle.com" - }, - "marketcap_usd": 40249218, - "name": "Bluzelle", - "network": "eth", - "shortcut": "BLZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BMT": { - "address": "0xf028ADEe51533b1B47BEaa890fEb54a457f51E89", - "links": { - "Github": "https://github.com/BMChain/BMChain-Token-Distribution-Interface", - "Homepage": "https://bmchain.io" - }, - "marketcap_usd": 0, - "name": "BMT", - "network": "eth", - "shortcut": "BMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BMX": { - "address": "0x986EE2B944c42D017F52Af21c4c69B84DBeA35d8", - "links": { - "Homepage": "https://www.bitmart.com" - }, - "marketcap_usd": 18049390, - "name": "BitMart Token", - "network": "eth", - "shortcut": "BMX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BNB": { - "address": "0xB8c77482e45F1F44dE1745F52C74426C631bDD52", - "links": { - "Homepage": "https://www.binance.com" - }, - "marketcap_usd": 0, - "name": "Binance Coin", - "network": "eth", - "shortcut": "BNB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BNN": { - "address": "0xDA80B20038BDF968C7307BB5907A469482CF6251", - "links": { - "Homepage": "https://www.brokerneko.com" - }, - "marketcap_usd": 0, - "name": "BrokerNekoNetwork", - "network": "eth", - "shortcut": "BNN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BNP": { - "address": "0xD27D76A1bA55ce5C0291CCd04feBBe793D22ebF4", - "links": { - "Github": "https://github.com/benepit/ERCContracts?from=groupmessage&isappinstalled=0", - "Homepage": "https://www.benepit.io" - }, - "marketcap_usd": 0, - "name": "Benepit Token", - "network": "eth", - "shortcut": "BNP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BNT": { - "address": "0x1F573D6Fb3F13d689FF844B4cE37794d79a7FF1C", - "links": { - "Github": "https://github.com/bancorprotocol", - "Homepage": "https://www.bancor.network" - }, - "marketcap_usd": 74533517, - "name": "Bancor Network Token", - "network": "eth", - "shortcut": "BNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BNTY": { - "address": "0xd2d6158683aeE4Cc838067727209a0aAF4359de3", - "links": { - "Homepage": "https://bounty0x.io" - }, - "marketcap_usd": 148222, - "name": "Bounty0x Token", - "network": "eth", - "shortcut": "BNTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOB": { - "address": "0xDF347911910b6c9A4286bA8E2EE5ea4a39eB2134", - "links": { - "Homepage": "https://bobsrepair.com" - }, - "marketcap_usd": 710785, - "name": "Bob's repair", - "network": "eth", - "shortcut": "BOB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOK": { - "address": "0x27C743954bCe1Bfaef8bcbD685527531001D88D7", - "links": { - "Homepage": "https://www.blockium.io/" - }, - "marketcap_usd": 0, - "name": "Blockium", - "network": "eth", - "shortcut": "BOK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOL": { - "address": "0xEfE98765Da3824eF4a5358bA798cec87c13D8C62", - "links": { - "Github": "https://github.com/freight-chain", - "Homepage": "http://www.freighttrust.com" - }, - "marketcap_usd": 0, - "name": "Freight Trust Protocol", - "network": "eth", - "shortcut": "BOL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOLT": { - "address": "0x9F235D23354857EfE6c541dB92a9eF1877689BCB", - "links": { - "Homepage": "https://www.bolt.global" - }, - "marketcap_usd": 0, - "name": "BOLT Token", - "network": "eth", - "shortcut": "BOLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BON": { - "address": "0xCc34366E3842cA1BD36c1f324d15257960fCC801", - "links": { - "Homepage": "https://bonpay.com" - }, - "marketcap_usd": 7918, - "name": "Bonpay", - "network": "eth", - "shortcut": "BON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOP": { - "address": "0x7F1E2C7d6A69bf34824D72C53B4550E895C0D8C2", - "links": { - "Homepage": "https://blockoptions.io" - }, - "marketcap_usd": 0, - "name": "BlockOptiopns Token", - "network": "eth", - "shortcut": "BOP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOU": { - "address": "0xC2C63F23ec5E97efbD7565dF9Ec764FDc7d4e91d", - "links": { - "Homepage": "https://www.boule.one" - }, - "marketcap_usd": 0, - "name": "Boule Coin", - "network": "eth", - "shortcut": "BOU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOUTS": { - "address": "0x139d9397274bb9E2C29A9aa8Aa0b5874d30D62E3", - "links": { - "Homepage": "https://www.bouts.pro" - }, - "marketcap_usd": 13777, - "name": "BoutsPro", - "network": "eth", - "shortcut": "BOUTS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BOXX": { - "address": "0x780116D91E5592E58a3b3c76A351571b39abCEc6", - "links": { - "Homepage": "https://www.goblockparty.com" - }, - "marketcap_usd": 0, - "name": "BOXX Token [Blockparty]", - "network": "eth", - "shortcut": "BOXX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BPF": { - "address": "0x5197FBE1a86679FF1360E27862BF88B0c5119BD8", - "links": { - "Github": "https://github.com/bitpif", - "Homepage": "https://bitpif.com" - }, - "marketcap_usd": 0, - "name": "BITPIF", - "network": "eth", - "shortcut": "BPF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BPT": { - "address": "0x327682779bAB2BF4d1337e8974ab9dE8275A7Ca8", - "links": { - "Github": "https://github.com/Blockport/tokensale", - "Homepage": "https://blockport.io" - }, - "marketcap_usd": 0, - "name": "Blockport Token", - "network": "eth", - "shortcut": "BPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BQX": { - "address": "0x5Af2Be193a6ABCa9c8817001F45744777Db30756", - "links": { - "Homepage": "https://www.bitquence.com" - }, - "marketcap_usd": 0, - "name": "Bitquence", - "network": "eth", - "shortcut": "BQX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRAT": { - "address": "0x9E77D5a1251b6F7D456722A6eaC6D2d5980bd891", - "links": { - "Homepage": "http://bro-consortium.io" - }, - "marketcap_usd": 0, - "name": "BROTHER", - "network": "eth", - "shortcut": "BRAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRD": { - "address": "0x558EC3152e2eb2174905cd19AeA4e34A23DE9aD6", - "links": { - "Github": "https://github.com/breadwallet", - "Homepage": "https://token.breadapp.com/en" - }, - "marketcap_usd": 544089, - "name": "Bread", - "network": "eth", - "shortcut": "BRD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRLN": { - "address": "0x80046305aaab08F6033b56a360c184391165dc2d", - "links": { - "Homepage": "https://berlin.bounties.network" - }, - "marketcap_usd": 0, - "name": "Berlin Coin", - "network": "eth", - "shortcut": "BRLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRP": { - "address": "0xB22c2786a549B008517B67625f5296E8fAf9589e", - "links": { - "Homepage": "https://bitherstock.io" - }, - "marketcap_usd": 0, - "name": "Rental Processor Token", - "network": "eth", - "shortcut": "BRP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRUH": { - "address": "0xe6D2a9fCD946E07826C6cdd919DA04763eA4D812", - "links": { - "Github": "https://github.com/bruhtokeno/bruhtokeno", - "Homepage": "https://bruhcrypto.org" - }, - "marketcap_usd": 0, - "name": "Bruh", - "network": "eth", - "shortcut": "BRUH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BRX": { - "address": "0x3A4A0D5b8dfAcd651EE28ed4fFEBf91500345489", - "links": { - "Github": "https://github.com/Filinomus/BerryX", - "Homepage": "https://polar-berry.com" - }, - "marketcap_usd": 0, - "name": "BerryX", - "network": "eth", - "shortcut": "BRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BSDC": { - "address": "0xF26ef5E0545384b7Dcc0f297F2674189586830DF", - "links": { - "Github": "https://github.com/BitsIdea/BitsIdea", - "Homepage": "http://bitsidea.org" - }, - "marketcap_usd": 0, - "name": "BSDC", - "network": "eth", - "shortcut": "BSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BST": { - "address": "0x509A38b7a1cC0dcd83Aa9d06214663D9eC7c7F4a", - "links": { - "Homepage": "https://blocksquare.io" - }, - "marketcap_usd": 0, - "name": "BlocksquareToken", - "network": "eth", - "shortcut": "BST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTC++": { - "address": "0x0327112423F3A68efdF1fcF402F6c5CB9f7C33fd", - "links": { - "Github": "https://github.com/pie-dao", - "Homepage": "https://piedao.org" - }, - "marketcap_usd": 0, - "name": "PieDAO BTC++", - "network": "eth", - "shortcut": "BTC++", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTCE": { - "address": "0x0886949c1b8C412860c4264Ceb8083d1365e86CF", - "links": { - "Homepage": "https://btcetoken.com" - }, - "marketcap_usd": 0, - "name": "EthereumBitcoin", - "network": "eth", - "shortcut": "BTCE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTCL": { - "address": "0x5acD19b9c91e596b1f062f18e3D02da7eD8D1e50", - "links": { - "Homepage": "http://btclite.org" - }, - "marketcap_usd": 0, - "name": "BTC Lite", - "network": "eth", - "shortcut": "BTCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTCONE": { - "address": "0x87f5E8c3425218837f3CB67dB941aF0C01323E56", - "links": { - "Homepage": "https://www.bitcoinone.io" - }, - "marketcap_usd": 0, - "name": "BitCoin One", - "network": "eth", - "shortcut": "BTCONE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTE": { - "address": "0x73dD069c299A5d691E9836243BcaeC9c8C1D8734", - "links": { - "Github": "https://github.com/bitcoineum/Sharkpool", - "Homepage": "http://bitcoineum.com/miner" - }, - "marketcap_usd": 0, - "name": "BTE", - "network": "eth", - "shortcut": "BTE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTH": { - "address": "0xFAd572db566E5234AC9Fc3d570c4EdC0050eAA92", - "links": { - "Homepage": "https://www.bytether.com" - }, - "marketcap_usd": 0, - "name": "Bytether", - "network": "eth", - "shortcut": "BTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTHR": { - "address": "0xa02e3bB9cEbc03952601B3724B4940e0845BeBcf", - "links": { - "Github": "https://github.com/bethereumproject", - "Homepage": "https://www.bethereum.com/" - }, - "marketcap_usd": 0, - "name": "Bethereum", - "network": "eth", - "shortcut": "BTHR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTK": { - "address": "0xdb8646F5b487B5Dd979FAC618350e85018F557d4", - "links": { - "Github": "https://github.com/bitcoin-token", - "Homepage": "https://btk.community" - }, - "marketcap_usd": 0, - "name": "Bitcoin Token", - "network": "eth", - "shortcut": "BTK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTM": { - "address": "0xcB97e65F07DA24D46BcDD078EBebd7C6E6E3d750", - "links": { - "Github": "https://github.com/bytom", - "Homepage": "https://bytom.io" - }, - "marketcap_usd": 0, - "name": "Bytom", - "network": "eth", - "shortcut": "BTM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTNG": { - "address": "0xD6b107D3E45B959B6d13FAF1bb2a2CF8fC7025e6", - "links": { - "Github": "https://github.com/bitnexglobal", - "Homepage": "https://bitnexglobal.com" - }, - "marketcap_usd": 0, - "name": "Bitnex Global", - "network": "eth", - "shortcut": "BTNG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTO": { - "address": "0x36905Fc93280f52362A1CBAB151F25DC46742Fb5", - "links": { - "Homepage": "https://www.bottos.org" - }, - "marketcap_usd": 464164, - "name": "Bottos", - "network": "eth", - "shortcut": "BTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTP": { - "address": "0x20900587e569E3D0B2609BCa6Fb3469765ed0920", - "links": { - "Github": "https://github.com/bitmarketnews", - "Homepage": "http://bitmarket.news" - }, - "marketcap_usd": 0, - "name": "Bitpoint", - "network": "eth", - "shortcut": "BTP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTQ": { - "address": "0x16B0E62aC13a2fAeD36D18bce2356d25Ab3CfAD3", - "links": { - "Homepage": "https://thebtcbtq.com" - }, - "marketcap_usd": 0, - "name": "Bitcoin Boutique", - "network": "eth", - "shortcut": "BTQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTRN": { - "address": "0x03C780cD554598592B97b7256dDAad759945b125", - "links": { - "Homepage": "https://biotron.io" - }, - "marketcap_usd": 0, - "name": "Biotron", - "network": "eth", - "shortcut": "BTRN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTU": { - "address": "0xb683D83a532e2Cb7DFa5275eED3698436371cc9f", - "links": { - "Github": "https://github.com/btuprotocol", - "Homepage": "https://btu-protocol.com" - }, - "marketcap_usd": 0, - "name": "BTU Protocol", - "network": "eth", - "shortcut": "BTU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BTY": { - "address": "0x9eecec130fb665d03a37289ee34C818Ee7F79926", - "links": { - "Github": "https://github.com/betty365", - "Homepage": "https://betty365.org" - }, - "marketcap_usd": 0, - "name": "BETTY", - "network": "eth", - "shortcut": "BTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BUC": { - "address": "0xCa3c18a65b802eC267f8f4802545e7F53D24C75e", - "links": { - "Homepage": "https://beeunity.org" - }, - "marketcap_usd": 0, - "name": "BeeUnity Chain", - "network": "eth", - "shortcut": "BUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BUSD": { - "address": "0x4Fabb145d64652a948d72533023f6E7A623C7C53", - "links": { - "Github": "https://github.com/paxosglobal/busd-contract", - "Homepage": "https://www.paxos.com/busd" - }, - "marketcap_usd": 10638728787, - "name": "Binance USD (BUSD)", - "network": "eth", - "shortcut": "BUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BWN": { - "address": "0x51a4F65463597CA4609C9a90eA3D5ab219Fbc85D", - "links": { - "Github": "https://github.com/Bitwings", - "Homepage": "https://bitwings.org/" - }, - "marketcap_usd": 0, - "name": "Bitwings", - "network": "eth", - "shortcut": "BWN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BWX": { - "address": "0xbD168CbF9d3a375B38dC51A202B5E8a4E52069Ed", - "links": { - "Homepage": "https://www.bluewhale.foundation" - }, - "marketcap_usd": 0, - "name": "Blue Whale Token", - "network": "eth", - "shortcut": "BWX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BZ": { - "address": "0x4375E7aD8A01B8eC3Ed041399f62D9Cd120e0063", - "links": { - "Homepage": "https://www.bitz.com" - }, - "marketcap_usd": 0, - "name": "Bit-Z Token", - "network": "eth", - "shortcut": "BZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:BZNT": { - "address": "0xE1Aee98495365fc179699C1bB3E761FA716beE62", - "links": { - "Homepage": "https://bezant.io" - }, - "marketcap_usd": 328936, - "name": "Bezant", - "network": "eth", - "shortcut": "BZNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:C10": { - "address": "0x000C100050E98C91f9114fa5Dd75CE6869Bf4F53", - "links": { - "Github": "https://github.com/invictuscapital", - "Homepage": "https://invictuscapital.com/crypto10hedged" - }, - "marketcap_usd": 0, - "name": "Token CRYPTO10 Hedged", - "network": "eth", - "shortcut": "C10", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:C20": { - "address": "0x26E75307Fc0C021472fEb8F727839531F112f317", - "links": { - "Github": "https://github.com/cryptotwenty", - "Homepage": "https://crypto20.com" - }, - "marketcap_usd": 1040095, - "name": "Crypto20's Token", - "network": "eth", - "shortcut": "C20", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:C8": { - "address": "0xd42debE4eDc92Bd5a3FBb4243e1ecCf6d63A4A5d", - "links": { - "Homepage": "https://www.carboneum.io" - }, - "marketcap_usd": 0, - "name": "Carboneum", - "network": "eth", - "shortcut": "C8", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CAG": { - "address": "0x7d4b8Cce0591C9044a22ee543533b72E976E36C3", - "links": { - "Homepage": "https://change-bank.com" - }, - "marketcap_usd": 0, - "name": "Change Bank", - "network": "eth", - "shortcut": "CAG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CALL": { - "address": "0xBbe761EA1447A20b75aA485b7BCad4837415d7D7", - "links": { - "Github": "https://github.com/Global-Crypto-Alliance/call-token", - "Homepage": "https://gcalliance.io" - }, - "marketcap_usd": 0, - "name": "CALL token", - "network": "eth", - "shortcut": "CALL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CAN": { - "address": "0x1d462414fe14cf489c7A21CaC78509f4bF8CD7c0", - "links": { - "Homepage": "https://canya.io" - }, - "marketcap_usd": 0, - "name": "CanYaCoin", - "network": "eth", - "shortcut": "CAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CAPP": { - "address": "0x04F2E7221fdb1B52A68169B25793E51478fF0329", - "links": { - "Homepage": "https://cappasity.com/tech/" - }, - "marketcap_usd": 0, - "name": "Cappasity", - "network": "eth", - "shortcut": "CAPP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CARB": { - "address": "0xA517a46Baad6B054A76bD19c46844f717fe69fea", - "links": { - "Homepage": "https://carbcoin.eu/" - }, - "marketcap_usd": 0, - "name": "CarbCoin", - "network": "eth", - "shortcut": "CARB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CARCO": { - "address": "0x2108E62D335Bbdc89eC3E9d8582F18DCFB0cDFf4", - "links": { - "Homepage": "https://carcohub.com" - }, - "marketcap_usd": 0, - "name": "CARCO", - "network": "eth", - "shortcut": "CARCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CARE": { - "address": "0xbF18F246B9301F231e9561B35A3879769BB46375", - "links": { - "Homepage": "https://tombcare.com/" - }, - "marketcap_usd": 0, - "name": "Token CARE", - "network": "eth", - "shortcut": "CARE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CBC": { - "address": "0x26DB5439F651CAF491A87d48799dA81F191bDB6b", - "links": { - "Homepage": "https://coin.cashbet.com" - }, - "marketcap_usd": 1412688, - "name": "CashBet Coin", - "network": "eth", - "shortcut": "CBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CBIX": { - "address": "0x05C3617cBf1304b9260AA61ec960F115D67beCEA", - "links": { - "Github": "https://github.com/Cubrixio", - "Homepage": "https://cubrix.io" - }, - "marketcap_usd": 0, - "name": "Cubrix", - "network": "eth", - "shortcut": "CBIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CBT": { - "address": "0x076C97e1c869072eE22f8c91978C99B4bcB02591", - "links": { - "Homepage": "https://www.commerceblock.com" - }, - "marketcap_usd": 0, - "name": "CommerceBlock", - "network": "eth", - "shortcut": "CBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CC3": { - "address": "0xc166038705FFBAb3794185b3a9D925632A1DF37D", - "links": { - "Homepage": "https://coalcoin.tech/en" - }, - "marketcap_usd": 0, - "name": "Coal Coin", - "network": "eth", - "shortcut": "CC3", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CCCX": { - "address": "0x378903a03FB2C3AC76BB52773e3CE11340377A32", - "links": { - "Homepage": "http://clippercoin.com" - }, - "marketcap_usd": 0, - "name": "Clipper Coin", - "network": "eth", - "shortcut": "CCCX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CCLC": { - "address": "0xd348e07A2806505B856123045d27aeeD90924b50", - "links": { - "Github": "https://github.com/lifechange-io/christ-coin", - "Homepage": "https://christcoins.io" - }, - "marketcap_usd": 0, - "name": "Christ Coin", - "network": "eth", - "shortcut": "CCLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CCO": { - "address": "0x679BADc551626e01B23CeecEFBc9B877EA18fc46", - "links": { - "Homepage": "https://ccore.io" - }, - "marketcap_usd": 15877, - "name": "Ccore", - "network": "eth", - "shortcut": "CCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CCT": { - "address": "0x336F646F87D9f6bC6Ed42Dd46E8b3fD9DbD15C22", - "links": { - "Homepage": "http://crystal-clear.io" - }, - "marketcap_usd": 0, - "name": "Crystal Clear Token", - "network": "eth", - "shortcut": "CCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CDL": { - "address": "0x8a95ca448A52C0ADf0054bB3402dC5e09CD6B232", - "links": { - "Github": "https://github.com/confideal", - "Homepage": "https://confideal.io" - }, - "marketcap_usd": 0, - "name": "Confideal", - "network": "eth", - "shortcut": "CDL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CEEK": { - "address": "0xb056c38f6b7Dc4064367403E26424CD2c60655e1", - "links": { - "Homepage": "https://www.ceek.com/" - }, - "marketcap_usd": 85892279, - "name": "CEEK VR Token", - "network": "eth", - "shortcut": "CEEK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CELR": { - "address": "0x4F9254C83EB525f9FCf346490bbb3ed28a81C667", - "links": { - "Github": "https://github.com/celer-network", - "Homepage": "https://www.celer.network/" - }, - "marketcap_usd": 145988517, - "name": "CelerToken", - "network": "eth", - "shortcut": "CELR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CEN": { - "address": "0x0bC61DdED5F6710c637cf8288Eb6058766ce1921", - "links": { - "Github": "https://github.com/coinsuperapi", - "Homepage": "https://www.coinsuper.com" - }, - "marketcap_usd": 0, - "name": "CEN", - "network": "eth", - "shortcut": "CEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CENNZ": { - "address": "0x1122B6a0E00DCe0563082b6e2953f3A943855c1F", - "links": { - "Homepage": "https://www.centrality.ai" - }, - "marketcap_usd": 20808822, - "name": "Centrality", - "network": "eth", - "shortcut": "CENNZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CET": { - "address": "0xF660cA1e228e7BE1fA8B4f5583145E31147FB577", - "links": { - "Github": "https://github.com/DICE-Money/", - "Homepage": "https://dice.money/" - }, - "marketcap_usd": 0, - "name": "DICE Money Dicet", - "network": "eth", - "shortcut": "CET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CFC": { - "address": "0x5Dff89a2caa4D76bc286F74D67Bd718eb834da61", - "links": { - "Homepage": "https://cryptfillcoin.com" - }, - "marketcap_usd": 0, - "name": "CryptFillCoin", - "network": "eth", - "shortcut": "CFC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CFI": { - "address": "0x12FEF5e57bF45873Cd9B62E9DBd7BFb99e32D73e", - "links": { - "Homepage": "https://cofound.it/" - }, - "marketcap_usd": 0, - "name": "Cofound.it", - "network": "eth", - "shortcut": "CFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CFTY": { - "address": "0x6956983F8B3Ce173B4AB84361AA0ad52f38D936f", - "links": { - "Github": "https://github.com/crafty-work", - "Homepage": "https://crafty.work/" - }, - "marketcap_usd": 0, - "name": "Crafty Token", - "network": "eth", - "shortcut": "CFTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CGT": { - "address": "0xF5238462E7235c7B62811567E63Dd17d12C2EAA0", - "links": { - "Github": "https://github.com/cache-token/cache-contract", - "Homepage": "https://cache.gold" - }, - "marketcap_usd": 2889849, - "name": "CACHE Gold", - "network": "eth", - "shortcut": "CGT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CHAI": { - "address": "0x06AF07097C9Eeb7fD685c692751D5C66dB49c215", - "links": { - "Github": "https://github.com/dapphub/chai", - "Homepage": "https://chai.money/" - }, - "marketcap_usd": 0, - "name": "Chai", - "network": "eth", - "shortcut": "CHAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CHP": { - "address": "0xf3db7560E820834658B590C96234c333Cd3D5E5e", - "links": { - "Homepage": "https://coinpoker.com" - }, - "marketcap_usd": 0, - "name": "CoinPoker", - "network": "eth", - "shortcut": "CHP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CHSB": { - "address": "0xba9d4199faB4f26eFE3551D490E3821486f135Ba", - "links": { - "Homepage": "https://swissborg.com" - }, - "marketcap_usd": 214599152, - "name": "SwissBorg", - "network": "eth", - "shortcut": "CHSB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CHX": { - "address": "0x1460a58096d80a50a2F1f956DDA497611Fa4f165", - "links": { - "Homepage": "https://weown.com" - }, - "marketcap_usd": 0, - "name": "Own", - "network": "eth", - "shortcut": "CHX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CIV": { - "address": "0x37fE0f067FA808fFBDd12891C0858532CFE7361d", - "links": { - "Github": "https://github.com/CivilizationCIV", - "Homepage": "https://civfund.org" - }, - "marketcap_usd": 9218468, - "name": "Civilization", - "network": "eth", - "shortcut": "CIV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CIYA": { - "address": "0xf75fBfa2f681860B9A6D19FC3FF3D34CB322E2D6", - "links": { - "Github": "https://github.com/cryptoriya", - "Homepage": "https://www.cryptoriya.com" - }, - "marketcap_usd": 0, - "name": "CRYPTORIYA", - "network": "eth", - "shortcut": "CIYA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CJT": { - "address": "0x3abdfF32F76b42E7635bdb7e425f0231A5F3aB17", - "links": { - "Homepage": "https://www.connectjob.io" - }, - "marketcap_usd": 0, - "name": "ConnectJob", - "network": "eth", - "shortcut": "CJT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CK": { - "address": "0x06012c8cf97BEaD5deAe237070F9587f8E7A266d", - "links": { - "Homepage": "https://cryptokitties.co" - }, - "marketcap_usd": 0, - "name": "CK", - "network": "eth", - "shortcut": "CK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CL": { - "address": "0xe81D72D14B1516e68ac3190a46C93302Cc8eD60f", - "links": { - "Homepage": "https://www.coinlancer.io" - }, - "marketcap_usd": 0, - "name": "Coinlancer", - "network": "eth", - "shortcut": "CL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CLB": { - "address": "0xb1c1Cb8C7c1992dba24e628bF7d38E71daD46aeB", - "links": { - "Github": "https://github.com/Cloudbric-Project", - "Homepage": "https://www.cloudbric.io/" - }, - "marketcap_usd": 0, - "name": "Cloudbric", - "network": "eth", - "shortcut": "CLB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CLL": { - "address": "0x3dC9a42fa7Afe57BE03c58fD7F4411b1E466C508", - "links": { - "Github": "https://github.com/CryptoLiveLeak/CLL-Token", - "Homepage": "https://www.cryptoliveleak.com/" - }, - "marketcap_usd": 0, - "name": "CryptoLiveLeak", - "network": "eth", - "shortcut": "CLL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CLN": { - "address": "0x4162178B78D6985480A308B2190EE5517460406D", - "links": { - "Github": "https://github.com/colucom/CLN-solidity", - "Homepage": "https://cln.network" - }, - "marketcap_usd": 0, - "name": "ColuLocalNetwork", - "network": "eth", - "shortcut": "CLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CLP": { - "address": "0x7FCE2856899a6806eeEf70807985fc7554C66340", - "links": { - "Homepage": "https://cryptolending.org" - }, - "marketcap_usd": 0, - "name": "CryptoLending", - "network": "eth", - "shortcut": "CLP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CLT": { - "address": "0x2001f2A0Cf801EcFda622f6C28fb6E10d803D969", - "links": { - "Homepage": "https://coinloan.io" - }, - "marketcap_usd": 0, - "name": "CoinLoan", - "network": "eth", - "shortcut": "CLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CMBT": { - "address": "0x3EDD235C3E840C1F29286B2e39370a255C7B6fdb", - "links": { - "Homepage": "https://www.coinmarketbrasil.com.br" - }, - "marketcap_usd": 0, - "name": "CMBToken", - "network": "eth", - "shortcut": "CMBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CMC": { - "address": "0x7e667525521cF61352e2E01b50FaaaE7Df39749a", - "links": { - "Homepage": "https://www.cryptomart.me" - }, - "marketcap_usd": 0, - "name": "CryptoMart", - "network": "eth", - "shortcut": "CMC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CMCT": { - "address": "0x47bc01597798DCD7506DCCA36ac4302fc93a8cFb", - "links": { - "Homepage": "https://crowdmachine.com" - }, - "marketcap_usd": 0, - "name": "Crowd Machine Compute Token", - "network": "eth", - "shortcut": "CMCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CMERGE": { - "address": "0xC48b4814fAEd1CCc885DD6fDe62A6474AeCbb19a", - "links": { - "Homepage": "https://app.coinmerge.io/" - }, - "marketcap_usd": 0, - "name": "Coin Merge", - "network": "eth", - "shortcut": "CMERGE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CNB": { - "address": "0xEBf2F9E8De960f64ec0fDCDa6Cb282423133347B", - "links": { - "Homepage": "https://canabio.net" - }, - "marketcap_usd": 0, - "name": "Canabio", - "network": "eth", - "shortcut": "CNB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CND": { - "address": "0xd4c435F5B09F855C3317c8524Cb1F586E42795fa", - "links": { - "Homepage": "https://cindicator.com" - }, - "marketcap_usd": 2370802, - "name": "Cindicator", - "network": "eth", - "shortcut": "CND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CNN": { - "address": "0x8713d26637CF49e1b6B4a7Ce57106AaBc9325343", - "links": { - "Homepage": "https://cnntoken.io" - }, - "marketcap_usd": 0, - "name": "Content Neutrality Network", - "network": "eth", - "shortcut": "CNN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CO2": { - "address": "0xB4b1D2C217EC0776584CE08D3DD98F90EDedA44b", - "links": { - "Github": "https://github.com/climatecoinio", - "Homepage": "https://climatecoin.io" - }, - "marketcap_usd": 0, - "name": "Climatecoin", - "network": "eth", - "shortcut": "CO2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CO2Bit": { - "address": "0x574B36BceD443338875d171CC377E691f7d4F887", - "links": { - "Homepage": "https://co2bit.com" - }, - "marketcap_usd": 0, - "name": "CO2Bit", - "network": "eth", - "shortcut": "CO2Bit", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COB": { - "address": "0xb2F7EB1f2c37645bE61d73953035360e768D81E6", - "links": { - "Github": "https://github.com/cobinhood", - "Homepage": "https://cobinhood.com" - }, - "marketcap_usd": 96081, - "name": "Cobinhood Token", - "network": "eth", - "shortcut": "COB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COBR": { - "address": "0x933DFC5622792b41245aB8313416cAF0ba885aE7", - "links": { - "Github": "https://github.com/coinbroker", - "Homepage": "https://coinbroker.hu" - }, - "marketcap_usd": 0, - "name": "CoinBroker", - "network": "eth", - "shortcut": "COBR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COFI": { - "address": "0x3136eF851592aCf49CA4C825131E364170FA32b3", - "links": { - "Github": "https://github.com/coinfi", - "Homepage": "https://www.coinfi.com" - }, - "marketcap_usd": 376891, - "name": "CoinFi Token", - "network": "eth", - "shortcut": "COFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COIL": { - "address": "0x0C91B015AbA6f7B4738dcD36E7410138b29ADC29", - "links": { - "Github": "https://github.com/CoinOil", - "Homepage": "https://coinoil.io/" - }, - "marketcap_usd": 0, - "name": "CoinOil", - "network": "eth", - "shortcut": "COIL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COMP": { - "address": "0xc00e94Cb662C3520282E6f5717214004A7f26888", - "links": { - "Github": "https://github.com/compound-finance", - "Homepage": "https://compound.finance" - }, - "marketcap_usd": 361396714, - "name": "Compound", - "network": "eth", - "shortcut": "COMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CORI": { - "address": "0x725B190Bc077FFde17Cf549AA8ba25e298550B18", - "links": { - "Homepage": "https://corrently.de/token/" - }, - "marketcap_usd": 0, - "name": "Corrently Invest Token", - "network": "eth", - "shortcut": "CORI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COSM": { - "address": "0xC4Bcd64CB216D49fD3C643A32762F34626b45a1a", - "links": { - "Homepage": "https://cosmochain.io" - }, - "marketcap_usd": 0, - "name": "Cosmo Coin", - "network": "eth", - "shortcut": "COSM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COTI": { - "address": "0xDDB3422497E61e13543BeA06989C0789117555c5", - "links": { - "Github": "https://github.com/coti-io", - "Homepage": "https://coti.io" - }, - "marketcap_usd": 101905846, - "name": "COTI", - "network": "eth", - "shortcut": "COTI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:COV": { - "address": "0xE2FB6529EF566a080e6d23dE0bd351311087D567", - "links": { - "Homepage": "https://covesting.io/" - }, - "marketcap_usd": 0, - "name": "Covesting", - "network": "eth", - "shortcut": "COV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPAL": { - "address": "0x31910AFF5545784755970aE1fBE7fE65d5F0eEa2", - "links": { - "Github": "https://github.com/creatorpal", - "Homepage": "http://creatorpal.net" - }, - "marketcap_usd": 0, - "name": "CreatorPAL", - "network": "eth", - "shortcut": "CPAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPAY": { - "address": "0x0Ebb614204E47c09B6C3FeB9AAeCad8EE060E23E", - "links": { - "Homepage": "https://cryptopay.me" - }, - "marketcap_usd": 0, - "name": "Cryptopay", - "network": "eth", - "shortcut": "CPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPC": { - "address": "0xfAE4Ee59CDd86e3Be9e8b90b53AA866327D7c090", - "links": { - "Homepage": "http://www.cpchain.io" - }, - "marketcap_usd": 1798478, - "name": "CPChain", - "network": "eth", - "shortcut": "CPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPEX": { - "address": "0xb787d4eAc8899730bb8C57fc3c998c49c5244ec0", - "links": { - "Github": "https://github.com/coinpulse", - "Homepage": "https://CoinPulse.io" - }, - "marketcap_usd": 0, - "name": "CoinPulseToken", - "network": "eth", - "shortcut": "CPEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPLO": { - "address": "0x7064aAb39A0Fcf7221c3396719D0917a65E35515", - "links": { - "Github": "https://github.com/Cpollo", - "Homepage": "https://cpollo.info/" - }, - "marketcap_usd": 0, - "name": "CPOLLO", - "network": "eth", - "shortcut": "CPLO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CPY": { - "address": "0xf44745fBd41F6A1ba151df190db0564c5fCc4410", - "links": { - "Github": "https://github.com/aditus", - "Homepage": "https://copytrack.io" - }, - "marketcap_usd": 0, - "name": "COPYTRACK", - "network": "eth", - "shortcut": "CPY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CR7": { - "address": "0x7F585B9130c64e9e9F470b618A7badD03D79cA7E", - "links": { - "Github": "https://github.com/CR7CoinProject", - "Homepage": "https://cr7coin.org" - }, - "marketcap_usd": 0, - "name": "CR7Coin", - "network": "eth", - "shortcut": "CR7", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRB": { - "address": "0xAef38fBFBF932D1AeF3B808Bc8fBd8Cd8E1f8BC5", - "links": { - "Homepage": "https://www.creditbit.org" - }, - "marketcap_usd": 0, - "name": "Creditbit", - "network": "eth", - "shortcut": "CRB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRBT": { - "address": "0x2cF618c19041D9Db330d8222B860A624021F30fb", - "links": { - "Homepage": "https://www.cruisebit.com" - }, - "marketcap_usd": 0, - "name": "Cruisebit", - "network": "eth", - "shortcut": "CRBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRC": { - "address": "0xF41e5Fbc2F6Aac200Dd8619E121CE1f05D150077", - "links": { - "Homepage": "https://crycash.io" - }, - "marketcap_usd": 0, - "name": "CryCash", - "network": "eth", - "shortcut": "CRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRED": { - "address": "0x672a1AD4f667FB18A333Af13667aa0Af1F5b5bDD", - "links": { - "Github": "https://github.com/verifyas", - "Homepage": "https://token.verify.as" - }, - "marketcap_usd": 0, - "name": "Verify", - "network": "eth", - "shortcut": "CRED", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CREDO": { - "address": "0x4E0603e2A27A30480E5e3a4Fe548e29EF12F64bE", - "links": { - "Homepage": "https://bitbounce.io" - }, - "marketcap_usd": 0, - "name": "Credo / Bitbounce", - "network": "eth", - "shortcut": "CREDO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRGO": { - "address": "0xf49CDD50aD408d387d611F88A647179C3de3492b", - "links": { - "Github": "https://github.com/CargoCoinRepo/Cargo-Coin", - "Homepage": "https://thecargocoin.com" - }, - "marketcap_usd": 0, - "name": "CargoCoin", - "network": "eth", - "shortcut": "CRGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRMT": { - "address": "0x9238bfB781A55eACC3Cf05F7DF94038c198CD9B9", - "links": { - "Homepage": "https://www.cremit.co" - }, - "marketcap_usd": 0, - "name": "Cremit", - "network": "eth", - "shortcut": "CRMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CRT": { - "address": "0xF0da1186a4977226b9135d0613ee72e229EC3F4d", - "links": { - "Homepage": "http://creamtoecoin.com" - }, - "marketcap_usd": 0, - "name": "CreamtoeCoin", - "network": "eth", - "shortcut": "CRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CS": { - "address": "0x46b9Ad944d1059450Da1163511069C718F699D31", - "links": { - "Homepage": "https://credits.com/en" - }, - "marketcap_usd": 1464121, - "name": "Credits", - "network": "eth", - "shortcut": "CS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CSNO": { - "address": "0x29D75277aC7F0335b2165D0895E8725cbF658d73", - "links": { - "Homepage": "https://www.bitdice.me" - }, - "marketcap_usd": 0, - "name": "BitDice", - "network": "eth", - "shortcut": "CSNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CST": { - "address": "0xBB49A51Ee5a66ca3a8CbE529379bA44Ba67E6771", - "links": { - "Homepage": "https://cryptosolartech.org" - }, - "marketcap_usd": 0, - "name": "Cryptosolartech", - "network": "eth", - "shortcut": "CST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTF": { - "address": "0x4545750F39aF6Be4F237B6869D4EccA928Fd5A85", - "links": { - "Github": "https://github.com/vkajic/cryptotask", - "Homepage": "http://www.cryptotask.org" - }, - "marketcap_usd": 0, - "name": "CryptoTask", - "network": "eth", - "shortcut": "CTF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTG": { - "address": "0xC87c5dD86A3d567fF28701886fB0745aaa898da4", - "links": { - "Github": "github.com/CTGlobal/ChristianTraders", - "Homepage": "https://christiantraders.com" - }, - "marketcap_usd": 0, - "name": "CT Global Token", - "network": "eth", - "shortcut": "CTG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTGC": { - "address": "0x9E7D29bd499B6c7da2a5B2EaFCF4A39d3BD845D1", - "links": { - "Github": "https://github.com/ctgcoin/", - "Homepage": "https://www.ctgcoin.org" - }, - "marketcap_usd": 0, - "name": "Convenient To Go", - "network": "eth", - "shortcut": "CTGC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTSI": { - "address": "0x491604c0FDF08347Dd1fa4Ee062a822A5DD06B5D", - "links": { - "Github": "https://github.com/cartesi", - "Homepage": "https://cartesi.io" - }, - "marketcap_usd": 108034607, - "name": "Cartesi Token", - "network": "eth", - "shortcut": "CTSI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTX": { - "address": "0x662aBcAd0b7f345AB7FfB1b1fbb9Df7894f18e66", - "links": { - "Homepage": "https://cartaxi.io" - }, - "marketcap_usd": 0, - "name": "CarTaxi", - "network": "eth", - "shortcut": "CTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CTXC": { - "address": "0xEa11755Ae41D889CeEc39A63E6FF75a02Bc1C00d", - "links": { - "Homepage": "http://www.cortexlabs.ai" - }, - "marketcap_usd": 0, - "name": "Cortex", - "network": "eth", - "shortcut": "CTXC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CUR8": { - "address": "0x490DBf7884B8e13c2161448b83Dd2d8909dB48eD", - "links": { - "Github": "https://github.com/curate-project", - "Homepage": "https://curate.style" - }, - "marketcap_usd": 0, - "name": "Curate", - "network": "eth", - "shortcut": "CUR8", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CURE": { - "address": "0x1dABF6Ab0eB8E4208E7E9302CeC7A014068952e4", - "links": { - "Homepage": "https://curate.style" - }, - "marketcap_usd": 0, - "name": "Curate", - "network": "eth", - "shortcut": "CURE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CVC": { - "address": "0x41e5560054824eA6B0732E656E3Ad64E20e94E45", - "links": { - "Homepage": "https://www.civic.com" - }, - "marketcap_usd": 118856816, - "name": "Civic", - "network": "eth", - "shortcut": "CVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CVS": { - "address": "0xdB56448fE2635f7912287cd619E7eD3d93180f25", - "links": { - "Github": "https://github.com/coinvisa", - "Homepage": "http://coinvisa.com" - }, - "marketcap_usd": 0, - "name": "CoinVisa", - "network": "eth", - "shortcut": "CVS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CVT": { - "address": "0xBe428c3867F05deA2A89Fc76a102b544eaC7f772", - "links": { - "Homepage": "http://www.cybervein.org" - }, - "marketcap_usd": 1632453, - "name": "CyberVein", - "network": "eth", - "shortcut": "CVT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CXC": { - "address": "0x2134057C0b461F898D375Cead652Acae62b59541", - "links": { - "Github": "https://github.com/coxxxcoin/smart_contract", - "Homepage": "http://coxxxcoin.com" - }, - "marketcap_usd": 0, - "name": "CoxxxCoin", - "network": "eth", - "shortcut": "CXC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CXO": { - "address": "0xb6EE9668771a79be7967ee29a63D4184F8097143", - "links": { - "Github": "https://github.com/cargoxio", - "Homepage": "https://cargox.io" - }, - "marketcap_usd": 0, - "name": "CargoX", - "network": "eth", - "shortcut": "CXO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CYCLE": { - "address": "0xfE831929098B5FF5d736105bD68BA9460EF07207", - "links": { - "Github": "https://github.com/cyclemontreal", - "Homepage": "http://cyclemontreal.net" - }, - "marketcap_usd": 0, - "name": "Cycle", - "network": "eth", - "shortcut": "CYCLE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CYFM": { - "address": "0x3f06B5D78406cD97bdf10f5C420B241D32759c80", - "links": { - "Homepage": "https://cyberfmradio.com" - }, - "marketcap_usd": 0, - "name": "CyberFM", - "network": "eth", - "shortcut": "CYFM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CYMT": { - "address": "0x78c292D1445E6b9558bf42e8BC369271DeD062eA", - "links": { - "Homepage": "https://cybermusic.io" - }, - "marketcap_usd": 252201, - "name": "CyberMusic", - "network": "eth", - "shortcut": "CYMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CZR": { - "address": "0x0223fc70574214F65813fE336D870Ac47E147fAe", - "links": { - "Homepage": "http://www.canonchain.com" - }, - "marketcap_usd": 0, - "name": "CanonChain", - "network": "eth", - "shortcut": "CZR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:CryptoCarbon": { - "address": "0xE4c94d45f7Aef7018a5D66f44aF780ec6023378e", - "links": { - "Homepage": "https://ccrb.io" - }, - "marketcap_usd": 0, - "name": "CryptoCarbon", - "network": "eth", - "shortcut": "CryptoCarbon", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAB": { - "address": "0xdab0C31BF34C897Fb0Fe90D12EC9401caf5c36Ec", - "links": { - "Github": "https://github.com/DABcoin", - "Homepage": "https://dabco.in" - }, - "marketcap_usd": 0, - "name": "DAB", - "network": "eth", - "shortcut": "DAB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DACS": { - "address": "0xA31108E5BAB5494560Db34c95492658AF239357C", - "links": { - "Homepage": "https://dacsee.io/#" - }, - "marketcap_usd": 0, - "name": "DACSEE", - "network": "eth", - "shortcut": "DACS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DADI": { - "address": "0xFb2f26F266Fb2805a387230f2aa0a331b4d96Fba", - "links": { - "Homepage": "https://dadi.cloud" - }, - "marketcap_usd": 0, - "name": "DADI", - "network": "eth", - "shortcut": "DADI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAF": { - "address": "0x1d0198829cBA768E4Ef2f762CD82842Bba3e3458", - "links": { - "Github": "https://github.com/daftoken/DAF", - "Homepage": "https://daftoken.io" - }, - "marketcap_usd": 0, - "name": "Diamonds are Forever", - "network": "eth", - "shortcut": "DAF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAI": { - "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", - "links": { - "Github": "https://github.com/makerdao", - "Homepage": "https://makerdao.com" - }, - "marketcap_usd": 5224409492, - "name": "Dai Stablecoin v2.0", - "network": "eth", - "shortcut": "DAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DALC": { - "address": "0x07D9e49Ea402194bf48A8276dAfB16E4eD633317", - "links": { - "Homepage": "http://www.dalecoin.org" - }, - "marketcap_usd": 0, - "name": "DaleCoin", - "network": "eth", - "shortcut": "DALC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAN": { - "address": "0x9B70740e708a083C6fF38Df52297020f5DfAa5EE", - "links": { - "Github": "https://github.com/project-daneel", - "Homepage": "https://daneel.io" - }, - "marketcap_usd": 0, - "name": "DaneelToken", - "network": "eth", - "shortcut": "DAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAT": { - "address": "0x81c9151de0C8bafCd325a57E3dB5a5dF1CEBf79c", - "links": { - "Homepage": "https://datum.org" - }, - "marketcap_usd": 0, - "name": "Datum Token", - "network": "eth", - "shortcut": "DAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DATA": { - "address": "0x8f693ca8D21b157107184d29D398A8D082b38b76", - "links": { - "Github": "https://github.com/streamr-dev", - "Homepage": "https://streamr.network/" - }, - "marketcap_usd": 31983242, - "name": "Streamr (DATA)", - "network": "eth", - "shortcut": "DATA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DATABroker": { - "address": "0x1B5f21ee98eed48d292e8e2d3Ed82b40a9728A22", - "links": { - "Github": "https://github.com/DataBrokerDAO", - "Homepage": "https://databrokerdao.com" - }, - "marketcap_usd": 0, - "name": "DataBrokerDAO Token", - "network": "eth", - "shortcut": "DATABroker", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DATX": { - "address": "0xaBbBB6447B68ffD6141DA77C18c7B5876eD6c5ab", - "links": { - "Homepage": "https://www.datx.co" - }, - "marketcap_usd": 0, - "name": "DATx", - "network": "eth", - "shortcut": "DATX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAV": { - "address": "0xd82Df0ABD3f51425Eb15ef7580fDA55727875f14", - "links": { - "Github": "https://github.com/DAVFoundation", - "Homepage": "https://dav.network/" - }, - "marketcap_usd": 713066, - "name": "DAV Token", - "network": "eth", - "shortcut": "DAV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAX": { - "address": "0x0B4BdC478791897274652DC15eF5C135cae61E60", - "links": { - "Homepage": "https://www.daex.io" - }, - "marketcap_usd": 2068186, - "name": "DAEX", - "network": "eth", - "shortcut": "DAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAXT": { - "address": "0x61725f3db4004AFE014745B21DAb1E1677CC328b", - "links": { - "Homepage": "https://www.daxt.io" - }, - "marketcap_usd": 0, - "name": "Digital Asset Exchange Token", - "network": "eth", - "shortcut": "DAXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DAY": { - "address": "0xE814aeE960a85208C3dB542C53E7D4a6C8D5f60F", - "links": { - "Github": "https://github.com/chronologic", - "Homepage": "https://chronologic.network" - }, - "marketcap_usd": 0, - "name": "ChronoLogic DAY", - "network": "eth", - "shortcut": "DAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DBET": { - "address": "0x9b68bFaE21DF5A510931A262CECf63f41338F264", - "links": { - "Homepage": "https://www.decent.bet" - }, - "marketcap_usd": 61736, - "name": "DecentBet", - "network": "eth", - "shortcut": "DBET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DCA": { - "address": "0x386Faa4703a34a7Fdb19Bec2e14Fd427C9638416", - "links": { - "Github": "https://github.com/dobetacceptbet", - "Homepage": "http://www.dobetacceptbet.com" - }, - "marketcap_usd": 0, - "name": "DoBetAcceptBet", - "network": "eth", - "shortcut": "DCA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DCB": { - "address": "0x2D8e1dd483008c6843b9CF644Bad7fB25bF52b84", - "links": { - "Github": "https://github.com/dcblabs", - "Homepage": "https://www.dcb.my" - }, - "marketcap_usd": 0, - "name": "Digital Coin", - "network": "eth", - "shortcut": "DCB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DCC": { - "address": "0xFFa93Aacf49297D51E211817452839052FDFB961", - "links": { - "Github": "https://github.com/DistributedBanking/DCC", - "Homepage": "http://dcc.finance" - }, - "marketcap_usd": 0, - "name": "Distributed Credit Chain", - "network": "eth", - "shortcut": "DCC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DCL": { - "address": "0x399A0e6FbEb3d74c85357439f4c8AeD9678a5cbF", - "links": { - "Homepage": "https://www.DisLedger.com" - }, - "marketcap_usd": 0, - "name": "DCL", - "network": "eth", - "shortcut": "DCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DCN": { - "address": "0x08d32b0da63e2C3bcF8019c9c5d849d7a9d791e6", - "links": { - "Github": "https://github.com/Dentacoin", - "Homepage": "https://dentacoin.com" - }, - "marketcap_usd": 1239469, - "name": "Dentacoin", - "network": "eth", - "shortcut": "DCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DDF": { - "address": "0xcC4eF9EEAF656aC1a2Ab886743E98e97E090ed38", - "links": { - "Github": "https://github.com/digitaldevelopersfund/ddf", - "Homepage": "https://www.digitaldevelopersfund.com" - }, - "marketcap_usd": 0, - "name": "DDF", - "network": "eth", - "shortcut": "DDF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DEB": { - "address": "0x151202C9c18e495656f372281F493EB7698961D5", - "links": { - "Homepage": "https://debitum.network/" - }, - "marketcap_usd": 0, - "name": "DEBITUM", - "network": "eth", - "shortcut": "DEB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DEEZ": { - "address": "0x075c60EE2cD308ff47873b38Bd9A0Fa5853382c4", - "links": { - "Github": "https://github.com/DeezNutsToken/DEEZ", - "Homepage": "https://deeznuts.in" - }, - "marketcap_usd": 0, - "name": "DeezNuts", - "network": "eth", - "shortcut": "DEEZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DELTA": { - "address": "0xDE1E0AE6101b46520cF66fDC0B1059c5cC3d106c", - "links": { - "Homepage": "https://deltachain.tech" - }, - "marketcap_usd": 0, - "name": "DeltaChain", - "network": "eth", - "shortcut": "DELTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DENT": { - "address": "0x3597bfD533a99c9aa083587B074434E61Eb0A258", - "links": { - "Homepage": "https://www.dentwireless.com" - }, - "marketcap_usd": 116975263, - "name": "DENT", - "network": "eth", - "shortcut": "DENT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DEW": { - "address": "0x20E94867794dBA030Ee287F1406E100d03C84Cd3", - "links": { - "Homepage": "https://www.dew.one" - }, - "marketcap_usd": 0, - "name": "DEW", - "network": "eth", - "shortcut": "DEW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DEX": { - "address": "0x497bAEF294c11a5f0f5Bea3f2AdB3073DB448B56", - "links": { - "Homepage": "https://www.coinbit.co.kr/" - }, - "marketcap_usd": 0, - "name": "DEX", - "network": "eth", - "shortcut": "DEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DF": { - "address": "0x431ad2ff6a9C365805eBaD47Ee021148d6f7DBe0", - "links": { - "Github": "https://github.com/dforcenetwork", - "Homepage": "https://dforce.network" - }, - "marketcap_usd": 23334461, - "name": "dForce Platform Token", - "network": "eth", - "shortcut": "DF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DGD": { - "address": "0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A", - "links": { - "Homepage": "https://digix.global/" - }, - "marketcap_usd": 8201143, - "name": "Digix DAO", - "network": "eth", - "shortcut": "DGD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DGPT": { - "address": "0xf6cFe53d6FEbaEEA051f400ff5fc14F0cBBDacA1", - "links": { - "Github": "https://github.com/digipulseio", - "Homepage": "https://www.digipulse.io" - }, - "marketcap_usd": 0, - "name": "DigiPulse", - "network": "eth", - "shortcut": "DGPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DGS": { - "address": "0x6aEDbF8dFF31437220dF351950Ba2a3362168d1b", - "links": { - "Github": "https://github.com/dragonglasscom", - "Homepage": "https://dragonglass.com/" - }, - "marketcap_usd": 0, - "name": "Dragonglass", - "network": "eth", - "shortcut": "DGS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DGX": { - "address": "0x4f3AfEC4E5a3F2A6a1A411DEF7D7dFe50eE057bF", - "links": { - "Github": "https://github.com/DigixGlobal", - "Homepage": "https://digix.global" - }, - "marketcap_usd": 2548238, - "name": "Digix Gold Token", - "network": "eth", - "shortcut": "DGX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DGX1": { - "address": "0x55b9a11c2e8351b4Ffc7b11561148bfaC9977855", - "links": { - "Github": "https://github.com/DigixGlobal", - "Homepage": "https://digix.global" - }, - "marketcap_usd": 0, - "name": "Digix Gold Token 1.0", - "network": "eth", - "shortcut": "DGX1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DICE": { - "address": "0x2e071D2966Aa7D8dECB1005885bA1977D6038A65", - "links": { - "Homepage": "https://etheroll.com" - }, - "marketcap_usd": 0, - "name": "Etheroll", - "network": "eth", - "shortcut": "DICE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DIRTY": { - "address": "0x4faB740779C73aA3945a5CF6025bF1b0e7F6349C", - "links": { - "Github": "https://github.com/nodezy/dirty_finance", - "Homepage": "https://dirty.finance/" - }, - "marketcap_usd": 0, - "name": "dirty.finance", - "network": "eth", - "shortcut": "DIRTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DIT": { - "address": "0xf14922001A2FB8541a433905437ae954419C2439", - "links": { - "Homepage": "https://inmediate.io" - }, - "marketcap_usd": 0, - "name": "Digital Insurance Token", - "network": "eth", - "shortcut": "DIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DIVX": { - "address": "0x13f11C9905A08ca76e3e853bE63D4f0944326C72", - "links": { - "Homepage": "https://www.diviproject.org" - }, - "marketcap_usd": 0, - "name": "DIVX", - "network": "eth", - "shortcut": "DIVX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DLT": { - "address": "0x07e3c70653548B04f0A75970C1F81B4CBbFB606f", - "links": { - "Homepage": "https://www.agrello.org" - }, - "marketcap_usd": 135781, - "name": "Agrello", - "network": "eth", - "shortcut": "DLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DMT": { - "address": "0x2ccbFF3A042c68716Ed2a2Cb0c544A9f1d1935E1", - "links": { - "Github": "https://github.com/suntechsoft/dmarket-smartcontract", - "Homepage": "https://dmarket.com" - }, - "marketcap_usd": 399206, - "name": "DMarket Token", - "network": "eth", - "shortcut": "DMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DNA": { - "address": "0xef6344de1fcfC5F48c30234C16c1389e8CdC572C", - "links": { - "Homepage": "https://encrypgen.com" - }, - "marketcap_usd": 0, - "name": "EncrypGen", - "network": "eth", - "shortcut": "DNA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DNT": { - "address": "0x0AbdAce70D3790235af448C88547603b945604ea", - "links": { - "Github": "https://github.com/district0x", - "Homepage": "https://district0x.io" - }, - "marketcap_usd": 21489851, - "name": "District0x Network Token", - "network": "eth", - "shortcut": "DNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DNX": { - "address": "0xE43E2041dc3786e166961eD9484a5539033d10fB", - "links": { - "Github": "https://github.com/DenCity-life", - "Homepage": "https://dencity.life" - }, - "marketcap_usd": 0, - "name": "DenCity", - "network": "eth", - "shortcut": "DNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DOCK": { - "address": "0xE5Dada80Aa6477e85d09747f2842f7993D0Df71C", - "links": { - "Homepage": "https://dock.io" - }, - "marketcap_usd": 0, - "name": "Dock", - "network": "eth", - "shortcut": "DOCK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DONK": { - "address": "0xE4F6D46C244Bb7Cf3e218CDFB5C35cf9a4d9c920", - "links": { - "Homepage": "https://www.projectdonkey.com" - }, - "marketcap_usd": 0, - "name": "Donkey", - "network": "eth", - "shortcut": "DONK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DOR": { - "address": "0x906b3f8b7845840188Eab53c3f5AD348A787752f", - "links": { - "Homepage": "https://www.dorado.tech" - }, - "marketcap_usd": 0, - "name": "Dorado", - "network": "eth", - "shortcut": "DOR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DOV": { - "address": "0xac3211a5025414Af2866FF09c23FC18bc97e79b1", - "links": { - "Homepage": "https://dovu.io" - }, - "marketcap_usd": 10302838, - "name": "Dovu", - "network": "eth", - "shortcut": "DOV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DPP": { - "address": "0x01b3Ec4aAe1B8729529BEB4965F27d008788B0EB", - "links": { - "Github": "https://github.com/DAPowerPlay", - "Homepage": "https://dapowerplay.com" - }, - "marketcap_usd": 0, - "name": "Digital Assets Power Play", - "network": "eth", - "shortcut": "DPP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DREAM": { - "address": "0x82f4dED9Cec9B5750FBFf5C2185AEe35AfC16587", - "links": { - "Homepage": "https://dreamteam.gg" - }, - "marketcap_usd": 0, - "name": "DREAM", - "network": "eth", - "shortcut": "DREAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DRGN": { - "address": "0x419c4dB4B9e25d6Db2AD9691ccb832C8D9fDA05E", - "links": { - "Github": "https://github.com/dragonchain/dragonchain", - "Homepage": "https://dragonchain.com" - }, - "marketcap_usd": 5066629, - "name": "Dragon", - "network": "eth", - "shortcut": "DRGN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DRPU": { - "address": "0xe30e02f049957e2A5907589e06Ba646fB2c321bA", - "links": { - "Homepage": "https://www.dcorp.it" - }, - "marketcap_usd": 0, - "name": "DCORP Utility", - "network": "eth", - "shortcut": "DRPU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DRT": { - "address": "0x9AF4f26941677C706cfEcf6D3379FF01bB85D5Ab", - "links": { - "Homepage": "https://token.domraider.com" - }, - "marketcap_usd": 138277, - "name": "DomRaider", - "network": "eth", - "shortcut": "DRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DRVH": { - "address": "0x62D4c04644314F35868Ba4c65cc27a77681dE7a9", - "links": { - "Github": "https://github.com/TeamDriveholic", - "Homepage": "https://driveholic.com/" - }, - "marketcap_usd": 0, - "name": "Driveholic Token", - "network": "eth", - "shortcut": "DRVH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DSC": { - "address": "0x1e09BD8Cadb441632e441Db3e1D79909EE0A2256", - "links": { - "Homepage": "https://github.com/xxxxyy1" - }, - "marketcap_usd": 0, - "name": "Digital Safe Coin", - "network": "eth", - "shortcut": "DSC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DSCP": { - "address": "0x03e3f0c25965f13DbbC58246738C183E27b26a56", - "links": { - "Github": "https://github.com/DisciplinaOU/disciplina", - "Homepage": "https://disciplina.io" - }, - "marketcap_usd": 0, - "name": "Disciplina Token", - "network": "eth", - "shortcut": "DSCP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DST": { - "address": "0x68d53441c0e253f76c500e551bdeA3D102206C9a", - "links": { - "Github": "https://github.com/DimensionsNetwork", - "Homepage": "https://dimensions.network/" - }, - "marketcap_usd": 0, - "name": "Dimensions Strike Token", - "network": "eth", - "shortcut": "DST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DTH": { - "address": "0x5adc961D6AC3f7062D2eA45FEFB8D8167d44b190", - "links": { - "Github": "https://github.com/dethertech", - "Homepage": "https://dether.io" - }, - "marketcap_usd": 0, - "name": "dether", - "network": "eth", - "shortcut": "DTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DTR": { - "address": "0xd234BF2410a0009dF9c3C63b610c09738f18ccD7", - "links": { - "Homepage": "https://www.tokens.net" - }, - "marketcap_usd": 0, - "name": "Dynamic Trading Rights", - "network": "eth", - "shortcut": "DTR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DTRC": { - "address": "0xc20464e0C373486d2B3335576e83a218b1618A5E", - "links": { - "Homepage": "https://datarius.io" - }, - "marketcap_usd": 37098, - "name": "Datarius Credit", - "network": "eth", - "shortcut": "DTRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DTT": { - "address": "0xf9F7c29CFdf19FCf1f2AA6B84aA367Bcf1bD1676", - "links": { - "Github": "https://github.com/DTToken", - "Homepage": "https://delphifund.org/" - }, - "marketcap_usd": 0, - "name": "Delphi Tech Token", - "network": "eth", - "shortcut": "DTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:DXT": { - "address": "0x8dB54ca569D3019A2ba126D03C37c44b5eF81EF6", - "links": { - "Homepage": "https://datawallet.com" - }, - "marketcap_usd": 0, - "name": "Datawallet", - "network": "eth", - "shortcut": "DXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:Devcon2 Token": { - "address": "0xdd94De9cFE063577051A5eb7465D08317d8808B6", - "links": { - "Homepage": "https://www.devcon2-token.com" - }, - "marketcap_usd": 0, - "name": "Devcon2 Token", - "network": "eth", - "shortcut": "Devcon2 Token", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EAGLE": { - "address": "0x994f0DffdbaE0BbF09b652D6f11A493fd33F42B9", - "links": { - "Github": "https://github.com/elangindonesia/EagleCoin", - "Homepage": "https://eaglepay.io" - }, - "marketcap_usd": 0, - "name": "EagleCoin", - "network": "eth", - "shortcut": "EAGLE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EARTH": { - "address": "0x900b4449236a7bb26b286601dD14d2bDe7a6aC6c", - "links": { - "Homepage": "https://earth-token.com" - }, - "marketcap_usd": 0, - "name": "Earth Token", - "network": "eth", - "shortcut": "EARTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EBC": { - "address": "0x31f3D9D1BeCE0c033fF78fA6DA60a6048F3E13c5", - "links": { - "Homepage": "https://ebcoin.io" - }, - "marketcap_usd": 0, - "name": "EBCoin", - "network": "eth", - "shortcut": "EBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EBTC": { - "address": "0xeB7C20027172E5d143fB030d50f91Cece2D1485D", - "links": { - "Github": "https://github.com/eBTCCommunityTrustToken/eBTC", - "Homepage": "https://ebitcoin.org" - }, - "marketcap_usd": 0, - "name": "eBitcoin", - "network": "eth", - "shortcut": "EBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ECGO": { - "address": "0xa01b656E49Efbb8210D882A1F1A4d10F5CadA8cc", - "links": { - "Github": "https://github.com/ecgoio", - "Homepage": "https://ecgo.io" - }, - "marketcap_usd": 0, - "name": "Eco Gold", - "network": "eth", - "shortcut": "ECGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ECN": { - "address": "0xa578aCc0cB7875781b7880903F4594D13cFa8B98", - "links": { - "Homepage": "http://www.cewrd.com" - }, - "marketcap_usd": 0, - "name": "ECN", - "network": "eth", - "shortcut": "ECN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ECO2": { - "address": "0x17F93475d2A978f527c3f7c44aBf44AdfBa60D5C", - "links": { - "Homepage": "http://www.ethco2.com" - }, - "marketcap_usd": 0, - "name": "EtherCO2", - "network": "eth", - "shortcut": "ECO2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ECOM": { - "address": "0x171D750d42d661B62C277a6B486ADb82348c3Eca", - "links": { - "Homepage": "https://omnitude.tech" - }, - "marketcap_usd": 0, - "name": "Omnitude", - "network": "eth", - "shortcut": "ECOM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDC": { - "address": "0xFA1DE2Ee97e4c10C94C91Cb2b5062b89Fb140b82", - "links": { - "Homepage": "https://www.edc.network" - }, - "marketcap_usd": 0, - "name": "Education Credits", - "network": "eth", - "shortcut": "EDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDG": { - "address": "0x08711D3B02C8758F2FB3ab4e80228418a7F8e39c", - "links": { - "Homepage": "https://edgeless.io" - }, - "marketcap_usd": 1489622, - "name": "Edgeless", - "network": "eth", - "shortcut": "EDG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDI": { - "address": "0x79C5a1Ae586322A07BfB60be36E1b31CE8C84A1e", - "links": { - "Github": "https://github.com/freight-chain", - "Homepage": "https://freighttrust.com/" - }, - "marketcap_usd": 0, - "name": "Freight Trust Network", - "network": "eth", - "shortcut": "EDI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDO": { - "address": "0xCeD4E93198734dDaFf8492d525Bd258D49eb388E", - "links": { - "Homepage": "https://eidoo.io" - }, - "marketcap_usd": 0, - "name": "Eidoo", - "network": "eth", - "shortcut": "EDO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDR": { - "address": "0xc528c28FEC0A90C083328BC45f587eE215760A0F", - "links": { - "Github": "https://github.com/EndorCoin", - "Homepage": "https://www.endor.com" - }, - "marketcap_usd": 0, - "name": "Endor Protocol Token", - "network": "eth", - "shortcut": "EDR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EDX": { - "address": "0xBF8d8F1242b95dfBAe532aF6B0F4463905415CC1", - "links": { - "Github": "https://github.com/edex-exchange", - "Homepage": "https://edex.exchange" - }, - "marketcap_usd": 0, - "name": "Edex", - "network": "eth", - "shortcut": "EDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EGG": { - "address": "0x999Aa6488f076e6765448f090Aba83FbB470fC99", - "links": { - "Github": "https://github.com/medcocoricos", - "Homepage": "https://cocoricos.io" - }, - "marketcap_usd": 0, - "name": "Egg Token", - "network": "eth", - "shortcut": "EGG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EGT": { - "address": "0x8e1b448EC7aDFc7Fa35FC2e885678bD323176E34", - "links": { - "Github": "https://github.com/egretia", - "Homepage": "https://www.egretia.io" - }, - "marketcap_usd": 1382423, - "name": "Egretia Token", - "network": "eth", - "shortcut": "EGT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EGX": { - "address": "0xa19bbEf64eFF0D060a653e4DF10a57B6d8006d3E", - "links": { - "Homepage": "https://www.enegra.com" - }, - "marketcap_usd": 0, - "name": "Enegra", - "network": "eth", - "shortcut": "EGX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EHT": { - "address": "0xf9F0FC7167c311Dd2F1e21E9204F87EBA9012fB2", - "links": { - "Github": "https://github.com/team-easyhomes", - "Homepage": "https://easyhomes.io" - }, - "marketcap_usd": 0, - "name": "EasyHomes", - "network": "eth", - "shortcut": "EHT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EKO": { - "address": "0xa6a840E50bCaa50dA017b91A0D86B8b2d41156EE", - "links": { - "Homepage": "https://echolink.info" - }, - "marketcap_usd": 16271, - "name": "EchoLink", - "network": "eth", - "shortcut": "EKO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EKT": { - "address": "0xBAb165dF9455AA0F2AeD1f2565520B91DDadB4c8", - "links": { - "Homepage": "http://ekt8.io" - }, - "marketcap_usd": 0, - "name": "EDUCare", - "network": "eth", - "shortcut": "EKT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ELEC": { - "address": "0xD49ff13661451313cA1553fd6954BD1d9b6E02b9", - "links": { - "Homepage": "https://electrify.asia" - }, - "marketcap_usd": 385598, - "name": "Electrify.Asia", - "network": "eth", - "shortcut": "ELEC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ELF": { - "address": "0xbf2179859fc6D5BEE9Bf9158632Dc51678a4100e", - "links": { - "Github": "https://github.com/aelfProject", - "Homepage": "https://aelf.io/" - }, - "marketcap_usd": 157530461, - "name": "ELF Token", - "network": "eth", - "shortcut": "ELF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ELIX": { - "address": "0xc8C6A31A4A806d3710A7B38b7B296D2fABCCDBA8", - "links": { - "Homepage": "https://elixirtoken.io" - }, - "marketcap_usd": 0, - "name": "Elixir Token", - "network": "eth", - "shortcut": "ELIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ELTCOIN": { - "address": "0x44197A4c44D6A059297cAf6be4F7e172BD56Caaf", - "links": { - "Github": "https://github.com/eltcoin", - "Homepage": "http://www.eltcoin.tech/" - }, - "marketcap_usd": 29287, - "name": "ELTCOIN", - "network": "eth", - "shortcut": "ELTCOIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ELY": { - "address": "0xa95592DCFfA3C080B4B40E459c5f5692F67DB7F8", - "links": { - "Github": "https://github.com/Elysian-ELY", - "Homepage": "https://elycoin.io" - }, - "marketcap_usd": 41694, - "name": "ELYCOIN", - "network": "eth", - "shortcut": "ELY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EMB": { - "address": "0x28B94F58B11aC945341329dBf2e5EF7F8Bd44225", - "links": { - "Github": "https://github.com/blockcollider", - "Homepage": "https://blockcollider.org" - }, - "marketcap_usd": 0, - "name": "Emblem", - "network": "eth", - "shortcut": "EMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EMON": { - "address": "0xb67b88a25708a35AE7c2d736D398D268CE4f7F83", - "links": { - "Github": "https://github.com/etheremon/smartcontract", - "Homepage": "https://www.etheremon.com/" - }, - "marketcap_usd": 0, - "name": "Etheremon", - "network": "eth", - "shortcut": "EMON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EMONT": { - "address": "0x95dAaaB98046846bF4B2853e23cba236fa394A31", - "links": { - "Homepage": "https://www.etheremon.com" - }, - "marketcap_usd": 0, - "name": "Etheremon Token", - "network": "eth", - "shortcut": "EMONT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EMT": { - "address": "0x9501BFc48897DCEEadf73113EF635d2fF7ee4B97", - "links": { - "Github": "https://github.com/easyMINE", - "Homepage": "https://easymine.io" - }, - "marketcap_usd": 0, - "name": "easyMINE Token", - "network": "eth", - "shortcut": "EMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EMV": { - "address": "0xB802b24E0637c2B87D2E8b7784C055BBE921011a", - "links": { - "Homepage": "http://emovieventure.com" - }, - "marketcap_usd": 0, - "name": "EMovieVenture", - "network": "eth", - "shortcut": "EMV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENC": { - "address": "0x039F5050dE4908f9b5ddF40A4F3Aa3f329086387", - "links": { - "Github": "https://github.com/ethernetcash", - "Homepage": "https://ethernet.cash" - }, - "marketcap_usd": 0, - "name": "Ethernet.Cash", - "network": "eth", - "shortcut": "ENC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENG": { - "address": "0xf0Ee6b27b759C9893Ce4f094b49ad28fd15A23e4", - "links": { - "Github": "https://github.com/enigmampc", - "Homepage": "https://enigma.co/" - }, - "marketcap_usd": 66749, - "name": "Enigma", - "network": "eth", - "shortcut": "ENG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENGT": { - "address": "0x5DBAC24e98E2a4f43ADC0DC82Af403fca063Ce2c", - "links": { - "Homepage": "https://engagementtoken.com" - }, - "marketcap_usd": 0, - "name": "Engagement Token", - "network": "eth", - "shortcut": "ENGT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENJ": { - "address": "0xF629cBd94d3791C9250152BD8dfBDF380E2a3B9c", - "links": { - "Github": "https://github.com/enjin/contracts", - "Homepage": "https://enjincoin.io" - }, - "marketcap_usd": 468951418, - "name": "ENJIN", - "network": "eth", - "shortcut": "ENJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENQ": { - "address": "0x16EA01aCB4b0Bca2000ee5473348B6937ee6f72F", - "links": { - "Github": "https://github.com/Enecuum", - "Homepage": "https://enecuum.com" - }, - "marketcap_usd": 3492342, - "name": "Enecuum", - "network": "eth", - "shortcut": "ENQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ENTRP": { - "address": "0x5BC7e5f0Ab8b2E10D2D0a3F21739FCe62459aeF3", - "links": { - "Github": "https://github.com/hut34", - "Homepage": "https://hut34.io/" - }, - "marketcap_usd": 0, - "name": "Hut34 Entropy Token", - "network": "eth", - "shortcut": "ENTRP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EPH": { - "address": "0x875089A734213cA39f0d93c2BbB8209827ec5e9f", - "links": { - "Github": "https://github.com/EuphoriaStore", - "Homepage": "https://euphoriatoken.com" - }, - "marketcap_usd": 0, - "name": "Euphoria", - "network": "eth", - "shortcut": "EPH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EPX": { - "address": "0x35BAA72038F127f9f8C8f9B491049f64f377914d", - "links": { - "Github": "https://github.com/EthPokerIO/ethpokerIO", - "Homepage": "https://ethPoker.io" - }, - "marketcap_usd": 0, - "name": "ethPoker.io EPX", - "network": "eth", - "shortcut": "EPX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EPY": { - "address": "0x50Ee674689d75C0f88E8f83cfE8c4B69E8fd590D", - "links": { - "Homepage": "https://emphy.io" - }, - "marketcap_usd": 0, - "name": "Emphy", - "network": "eth", - "shortcut": "EPY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EQL": { - "address": "0x47dD62D4D075DeAd71d0e00299fc56a2d747beBb", - "links": { - "Homepage": "http://www.equaltoken.io" - }, - "marketcap_usd": 0, - "name": "Equal", - "network": "eth", - "shortcut": "EQL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ERO": { - "address": "0x74CEDa77281b339142A36817Fa5F9E29412bAb85", - "links": { - "Homepage": "https://eroscoin.org" - }, - "marketcap_usd": 43656, - "name": "Eroscoin", - "network": "eth", - "shortcut": "ERO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ERT": { - "address": "0x92A5B04D0ED5D94D7a193d1d334D3D16996f4E13", - "links": { - "Github": "https://github.com/Krishtopa/ContractEristica", - "Homepage": "https://eristica.com/" - }, - "marketcap_usd": 0, - "name": "Eristica", - "network": "eth", - "shortcut": "ERT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ESB": { - "address": "0x369760eBf89d577a734d927a9599C1921397A152", - "links": { - "Github": "https://github.com/eshipptoken", - "Homepage": "https://e-shipp.com" - }, - "marketcap_usd": 0, - "name": "E-Shipp Block", - "network": "eth", - "shortcut": "ESB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ESZ": { - "address": "0xe8A1Df958bE379045E2B46a31A98B93A2eCDfDeD", - "links": { - "Github": "https://github.com/EtherSportz/ESZCoin", - "Homepage": "https://ethersportz.com" - }, - "marketcap_usd": 0, - "name": "ESZCoin", - "network": "eth", - "shortcut": "ESZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETBS": { - "address": "0x1B9743f556D65e757c4c650B4555bAF354cB8bd3", - "links": { - "Homepage": "https://www.ethbits.com" - }, - "marketcap_usd": 0, - "name": "Ethbits", - "network": "eth", - "shortcut": "ETBS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETCH": { - "address": "0xDd74a7A3769fA72561B3A69e65968F49748c690c", - "links": { - "Homepage": "https://etch.work" - }, - "marketcap_usd": 0, - "name": "ETCH", - "network": "eth", - "shortcut": "ETCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETG": { - "address": "0x28c8d01FF633eA9Cd8fc6a451D7457889E698de6", - "links": { - "Homepage": "https://www.etgproject.org" - }, - "marketcap_usd": 0, - "name": "Ethereum Gold", - "network": "eth", - "shortcut": "ETG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETHB": { - "address": "0x3a26746Ddb79B1B8e4450e3F4FFE3285A307387E", - "links": { - "Homepage": "https://etherbtc.io/faq" - }, - "marketcap_usd": 0, - "name": "EtherBTC", - "network": "eth", - "shortcut": "ETHB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETHBNT": { - "address": "0xb1CD6e4153B2a390Cf00A6556b0fC1458C4A5533", - "links": { - "Github": "https://github.com/bancorprotocol", - "Homepage": "https://www.bancor.network" - }, - "marketcap_usd": 0, - "name": "Bancor ETH/BNT Liquidity Pool", - "network": "eth", - "shortcut": "ETHBNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETHPAY": { - "address": "0xE52e75e8a97546f40991b489E92c68eBb386dc97", - "links": { - "Homepage": "http://ethpay.im" - }, - "marketcap_usd": 0, - "name": "ETHPAY", - "network": "eth", - "shortcut": "ETHPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETK": { - "address": "0x3c4a3ffd813a107febd57B2f01BC344264D90FdE", - "links": { - "Homepage": "https://energitoken.com" - }, - "marketcap_usd": 0, - "name": "EnergiToken", - "network": "eth", - "shortcut": "ETK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ETR": { - "address": "0x6927C69fb4daf2043fbB1Cb7b86c5661416bea29", - "links": { - "Github": "https://github.com/pironmind/EthereumRisen", - "Homepage": "http://ethereumrisen.io" - }, - "marketcap_usd": 0, - "name": "Etheruem Risen", - "network": "eth", - "shortcut": "ETR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EUCX": { - "address": "0xd99298985902C9A69bf4C8a0895fA10721204ECC", - "links": { - "Github": "https://github.com/eucxio", - "Homepage": "https://eucx.io" - }, - "marketcap_usd": 0, - "name": "EUCX Token", - "network": "eth", - "shortcut": "EUCX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EURS": { - "address": "0xdB25f211AB05b1c97D595516F45794528a807ad8", - "links": { - "Github": "https://github.com/stasisnet", - "Homepage": "https://stasis.net" - }, - "marketcap_usd": 130380616, - "name": "STASIS EURS", - "network": "eth", - "shortcut": "EURS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EURT": { - "address": "0xAbdf147870235FcFC34153828c769A70B3FAe01F", - "links": { - "Homepage": "https://tether.to" - }, - "marketcap_usd": 0, - "name": "EUR Tether (erc20)", - "network": "eth", - "shortcut": "EURT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVC": { - "address": "0xb62d18DeA74045E822352CE4B3EE77319DC5ff2F", - "links": { - "Homepage": "https://eventchain.io" - }, - "marketcap_usd": 26440, - "name": "EventChain", - "network": "eth", - "shortcut": "EVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVCO": { - "address": "0xAa5C28be0F1173612eA3fCC9e461cCB7b9390213", - "links": { - "Homepage": "http://evcoin.us" - }, - "marketcap_usd": 0, - "name": "EVCOIN", - "network": "eth", - "shortcut": "EVCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVE": { - "address": "0x923108a439C4e8C2315c4f6521E5cE95B44e9B4c", - "links": { - "Github": "https://github.com/devery", - "Homepage": "https://devery.io" - }, - "marketcap_usd": 0, - "name": "Devery", - "network": "eth", - "shortcut": "EVE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVED": { - "address": "0x5aaEFe84E0fB3DD1f0fCfF6fA7468124986B91bd", - "links": { - "Github": "https://github.com/evedo-co", - "Homepage": "https://www.evedo.co" - }, - "marketcap_usd": 394579, - "name": "Evedo Token", - "network": "eth", - "shortcut": "EVED", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVF": { - "address": "0xA26C4caaaEa8b88ef49Bf8c380488f66C2d807Ae", - "links": { - "Github": "https://github.com/eviff", - "Homepage": "http://eviff.com" - }, - "marketcap_usd": 0, - "name": "Eviff", - "network": "eth", - "shortcut": "EVF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVO": { - "address": "0x442d985EFeBC633b8Bfd14fF99E860A5609a6484", - "links": { - "Github": "https://github.com/ethavo", - "Homepage": "https://ethavo.com" - }, - "marketcap_usd": 0, - "name": "Ethavo", - "network": "eth", - "shortcut": "EVO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EVX": { - "address": "0xf3Db5Fa2C66B7aF3Eb0C0b782510816cbe4813b8", - "links": { - "Homepage": "https://everex.io " - }, - "marketcap_usd": 338085, - "name": "Everex", - "network": "eth", - "shortcut": "EVX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EWO": { - "address": "0x444997b7e7fC830E20089afea3078cd518fCF2A2", - "links": { - "Github": "https://github.com/ewoplace", - "Homepage": "https://www.ewoplace.com/" - }, - "marketcap_usd": 0, - "name": "EWO Token", - "network": "eth", - "shortcut": "EWO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXE": { - "address": "0x0D9A653f681168f410d14D19B7743C041EafC58a", - "links": { - "Github": "https://github.com/EinsteinCash/", - "Homepage": "https://einstein.exchange/einstein-cash" - }, - "marketcap_usd": 0, - "name": "EinsteinCash", - "network": "eth", - "shortcut": "EXE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXMR": { - "address": "0xc98e0639c6d2EC037A615341c369666B110e80E5", - "links": { - "Github": "https://github.com/eXMRcoin/", - "Homepage": "https://exmr.io/" - }, - "marketcap_usd": 0, - "name": "eXMRcoin", - "network": "eth", - "shortcut": "EXMR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXR": { - "address": "0xFFee4DB0f30a43955398776A9524fDFF0680dD7f", - "links": { - "Homepage": "https://exserio.com/" - }, - "marketcap_usd": 0, - "name": "EXSERION Token", - "network": "eth", - "shortcut": "EXR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXRN": { - "address": "0xe469c4473af82217B30CF17b10BcDb6C8c796e75", - "links": { - "Homepage": "https://exrnchain.com" - }, - "marketcap_usd": 1505076, - "name": "EXRNchain", - "network": "eth", - "shortcut": "EXRN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXU": { - "address": "0xe06Af951086EC3c488b50E31BE29c07F8a260cA3", - "links": { - "Github": "https://github.com/EXUofficial", - "Homepage": "https://exu.io" - }, - "marketcap_usd": 0, - "name": "EXU Protocol", - "network": "eth", - "shortcut": "EXU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EXY": { - "address": "0x5c743a35E903F6c584514ec617ACEe0611Cf44f3", - "links": { - "Homepage": "https://experty.io/en" - }, - "marketcap_usd": 0, - "name": "Experty", - "network": "eth", - "shortcut": "EXY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:EZT": { - "address": "0x5e6016Ae7d7C49d347dcF834860B9f3Ee282812b", - "links": { - "Homepage": "https://ico.ezpos.io" - }, - "marketcap_usd": 0, - "name": "EZToken", - "network": "eth", - "shortcut": "EZT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:E\u20b9": { - "address": "0xb67734521eAbBE9C773729dB73E16CC2dfb20A58", - "links": { - "Github": "https://github.com/eRupee", - "Homepage": "https://erupee.wordpress.com" - }, - "marketcap_usd": 0, - "name": "eRupee", - "network": "eth", - "shortcut": "E\u20b9", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FABA": { - "address": "0x0a1D2fF7156a48131553CF381F220bbedB4eFa37", - "links": { - "Homepage": "https://vc.fabainvest.com" - }, - "marketcap_usd": 0, - "name": "FABA", - "network": "eth", - "shortcut": "FABA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FACE": { - "address": "0x1CCAA0F2a7210d76E1fDec740d5F323E2E1b1672", - "links": { - "Homepage": "https://tokensale.faceter.io" - }, - "marketcap_usd": 0, - "name": "Faceter", - "network": "eth", - "shortcut": "FACE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FAM": { - "address": "0x190e569bE071F40c704e15825F285481CB74B6cC", - "links": { - "Github": "https://github.com/BattleDrome", - "Homepage": "http://www.battledrome.io" - }, - "marketcap_usd": 0, - "name": "FAM", - "network": "eth", - "shortcut": "FAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FAN": { - "address": "0x90162f41886c0946D09999736f1C15c8a105A421", - "links": { - "Homepage": "https://tokensale.fanfare.global" - }, - "marketcap_usd": 0, - "name": "Fan Token", - "network": "eth", - "shortcut": "FAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FAR": { - "address": "0x7cf6dC769482AbEe2FF75795d000F381A8062DEC", - "links": { - "Github": "https://github.com/FarToken", - "Homepage": "http://fargoldtoken.com" - }, - "marketcap_usd": 0, - "name": "Far Token", - "network": "eth", - "shortcut": "FAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FARM": { - "address": "0x41f723448433367BE140D528D35EFECd3e023DB6", - "links": { - "Github": "https://github.com/farm-partner", - "Homepage": "https://agric.io" - }, - "marketcap_usd": 0, - "name": "Farm Partner", - "network": "eth", - "shortcut": "FARM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FDZ": { - "address": "0x23352036E911A22Cfc692B5E2E196692658ADED9", - "links": { - "Homepage": "https://friendz.io" - }, - "marketcap_usd": 22710, - "name": "Friendz", - "network": "eth", - "shortcut": "FDZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FER": { - "address": "0x4E594479Fa417a1e9C5790a413575802D393010F", - "links": { - "Github": "https://github.com/TheFerretCoin", - "Homepage": "http://theferretcoin.com" - }, - "marketcap_usd": 0, - "name": "Ferret Coin", - "network": "eth", - "shortcut": "FER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FGP": { - "address": "0xd9A8cfe21C232D485065cb62a96866799d4645f7", - "links": { - "Github": "https://github.com/FGPTEAM/FingerPrint", - "Homepage": "https://fingerprintcoin.org/" - }, - "marketcap_usd": 0, - "name": "FingerPrint", - "network": "eth", - "shortcut": "FGP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FID": { - "address": "0x52fb36C83ad33C1824912FC81071cA5eEB8AB390", - "links": { - "Homepage": "http://www.fidelium.io" - }, - "marketcap_usd": 0, - "name": "Fidelium", - "network": "eth", - "shortcut": "FID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FIG": { - "address": "0x2A73CB91ED8983398F83082c093ac306cac209FF", - "links": { - "Github": "https://github.com/fanboyscomiccon", - "Homepage": "http://fanboyscomiccon.com" - }, - "marketcap_usd": 0, - "name": "Fanboys Interactive", - "network": "eth", - "shortcut": "FIG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FIH": { - "address": "0xdfC3e857c8cCEA7657E0ed98AB92e048e38deE0f", - "links": { - "Github": "https://github.com/FidelityHouseInternational", - "Homepage": "https://www.fidelityhouse.io" - }, - "marketcap_usd": 0, - "name": "FidelityHouse Token", - "network": "eth", - "shortcut": "FIH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FKX": { - "address": "0x009e864923b49263c7F10D19B7f8Ab7a9A5AAd33", - "links": { - "Github": "https://github.com/FortKnoxster", - "Homepage": "https://fortknoxster.com" - }, - "marketcap_usd": 0, - "name": "Knoxstertoken", - "network": "eth", - "shortcut": "FKX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FLIXX": { - "address": "0xf04a8ac553FceDB5BA99A64799155826C136b0Be", - "links": { - "Homepage": "https://www.flixxo.com" - }, - "marketcap_usd": 739558, - "name": "Flixxo", - "network": "eth", - "shortcut": "FLIXX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FLOT": { - "address": "0x049399a6B048D52971F7D122aE21A1532722285F", - "links": { - "Homepage": "https://firelotto.io" - }, - "marketcap_usd": 32076, - "name": "Fire Lotto", - "network": "eth", - "shortcut": "FLOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FLP": { - "address": "0x3a1Bda28AdB5B0a812a7CF10A1950c920F79BcD3", - "links": { - "Github": "https://github.com/gameflip", - "Homepage": "https://gameflip.com" - }, - "marketcap_usd": 439780, - "name": "FLIP Token", - "network": "eth", - "shortcut": "FLP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FLR": { - "address": "0x9aeFBE0b3C3ba9Eab262CB9856E8157AB7648e09", - "links": { - "Homepage": "https://flaircoin.co/" - }, - "marketcap_usd": 0, - "name": "Flair Coin", - "network": "eth", - "shortcut": "FLR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FLUZ": { - "address": "0x954b5De09A55e59755aCBda29e1Eb74A45D30175", - "links": { - "Homepage": "https://ico.fluzfluz.com" - }, - "marketcap_usd": 0, - "name": "Fluz Fluz Global", - "network": "eth", - "shortcut": "FLUZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FMF": { - "address": "0xb4d0FDFC8497AEF97d3c2892AE682eE06064A2BC", - "links": { - "Github": "https://github.com/FormosaFinancial", - "Homepage": "https://www.formosa.financial/" - }, - "marketcap_usd": 0, - "name": "Formosa Financial Token", - "network": "eth", - "shortcut": "FMF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FMTA": { - "address": "0xAa9D866666C2A3748d6B23Ff69E63E52f08d9AB4", - "links": { - "Github": "https://github.com/civitas-fundamenta", - "Homepage": "https://fundamenta.network" - }, - "marketcap_usd": 0, - "name": "Fundamenta", - "network": "eth", - "shortcut": "FMTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FND": { - "address": "0x4DF47B4969B2911C966506E3592c41389493953b", - "links": { - "Github": "https://github.com/FundRequest", - "Homepage": "https://fundrequest.io" - }, - "marketcap_usd": 0, - "name": "FundRequest", - "network": "eth", - "shortcut": "FND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FNKOS": { - "address": "0x0707681F344dEB24184037fC0228856F2137B02E", - "links": { - "Homepage": "https://www.foglink.io" - }, - "marketcap_usd": 0, - "name": "FNKOS", - "network": "eth", - "shortcut": "FNKOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FNTB": { - "address": "0xbD4B60a138b3fce3584EA01f50c0908c18f9677A", - "links": { - "Homepage": "https://fintab.io/ico" - }, - "marketcap_usd": 0, - "name": "Fintab", - "network": "eth", - "shortcut": "FNTB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FOAM": { - "address": "0x4946Fcea7C692606e8908002e55A582af44AC121", - "links": { - "Github": "https://github.com/f-o-a-m", - "Homepage": "http://foam.space" - }, - "marketcap_usd": 4813660, - "name": "FOAM Token", - "network": "eth", - "shortcut": "FOAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FOOD": { - "address": "0x2a093BcF0C98Ef744Bb6F69D74f2F85605324290", - "links": { - "Homepage": "https://www.foodcoin.io" - }, - "marketcap_usd": 0, - "name": "FoodCoin", - "network": "eth", - "shortcut": "FOOD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FORK": { - "address": "0x5bB1632fA0023e1AA76a1AE92B4635C8DBa49Fa2", - "links": { - "Github": "https://github.com/gastroadvisor", - "Homepage": "https://www.gastroadvisor.com" - }, - "marketcap_usd": 0, - "name": "GastroAdvisorToken", - "network": "eth", - "shortcut": "FORK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FOTA": { - "address": "0x4270bb238f6DD8B1c3ca01f96CA65b2647c06D3C", - "links": { - "Homepage": "https://www.fota.io" - }, - "marketcap_usd": 0, - "name": "Fortuna", - "network": "eth", - "shortcut": "FOTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FOX": { - "address": "0xc770EEfAd204B5180dF6a14Ee197D99d808ee52d", - "links": { - "Homepage": "https://shapeshift.com" - }, - "marketcap_usd": 14439774, - "name": "FOX", - "network": "eth", - "shortcut": "FOX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FR8": { - "address": "0x8c39afDf7B17F12c553208555E51ab86E69C35aA", - "links": { - "Github": "https://github.com/fr8network", - "Homepage": "https://www.fr8.network" - }, - "marketcap_usd": 0, - "name": "Fr8 Network", - "network": "eth", - "shortcut": "FR8", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FRD": { - "address": "0x0ABeFb7611Cb3A01EA3FaD85f33C3C934F8e2cF4", - "links": { - "Homepage": "https://farad.energy" - }, - "marketcap_usd": 0, - "name": "FARAD Cryptoken", - "network": "eth", - "shortcut": "FRD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FREC": { - "address": "0x17e67d1CB4e349B9CA4Bc3e17C7DF2a397A7BB64", - "links": { - "Homepage": "http://www.freyrchain.org" - }, - "marketcap_usd": 0, - "name": "Freyrchain", - "network": "eth", - "shortcut": "FREC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FRECNX": { - "address": "0xd8B8E1Eca89dA014E67fDbc2014eaA8E171079bF", - "links": { - "Github": "https://github.com/FreldoZL/FreldoCoinX", - "Homepage": "https://ico.freldo.com/" - }, - "marketcap_usd": 0, - "name": "FreldoCoinX", - "network": "eth", - "shortcut": "FRECNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FRX": { - "address": "0x36a73557f5BDE5195EC39eCA82d28b8A36D21141", - "links": { - "Github": "https://github.com/FSRsystem", - "Homepage": "https://forexsmartsystem.com" - }, - "marketcap_usd": 0, - "name": "Forex Coin", - "network": "eth", - "shortcut": "FRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FT": { - "address": "0x78a73B6CBc5D183CE56e786f6e905CaDEC63547B", - "links": { - "Homepage": "https://fabrictoken.io" - }, - "marketcap_usd": 0, - "name": "Fabric Token", - "network": "eth", - "shortcut": "FT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTI": { - "address": "0x943ED852DadB5C3938ECdC6883718df8142DE4C8", - "links": { - "Homepage": "https://fanstime.org" - }, - "marketcap_usd": 147781, - "name": "FansTime", - "network": "eth", - "shortcut": "FTI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTM": { - "address": "0x4E15361FD6b4BB609Fa63C81A2be19d873717870", - "links": { - "Github": "https://github.com/Fantom-foundation/", - "Homepage": "https://fantom.foundation/" - }, - "marketcap_usd": 1245702872, - "name": "Fantom Token", - "network": "eth", - "shortcut": "FTM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTR": { - "address": "0x2023DCf7c438c8C8C0B0F28dBaE15520B4f3Ee20", - "links": { - "Homepage": "https://futourist.io/" - }, - "marketcap_usd": 0, - "name": "Futourist Token", - "network": "eth", - "shortcut": "FTR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTT": { - "address": "0x2AEC18c5500f21359CE1BEA5Dc1777344dF4C0Dc", - "links": { - "Github": "https://github.com/farmatrust", - "Homepage": "https://www.farmatrust.io" - }, - "marketcap_usd": 0, - "name": "FarmaTrust Token", - "network": "eth", - "shortcut": "FTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTX": { - "address": "0xd559f20296FF4895da39b5bd9ADd54b442596a61", - "links": { - "Homepage": "https://www.fintrux.com" - }, - "marketcap_usd": 176615, - "name": "FintruX Network", - "network": "eth", - "shortcut": "FTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FTXT": { - "address": "0x41875C2332B0877cDFAA699B641402b7D4642c32", - "links": { - "Github": "https://github.com/futuraxproject", - "Homepage": "https://futurax.global" - }, - "marketcap_usd": 55426, - "name": "FUTURAX", - "network": "eth", - "shortcut": "FTXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FUEL": { - "address": "0xEA38eAa3C86c8F9B751533Ba2E562deb9acDED40", - "links": { - "Github": "https://github.com/etherparty", - "Homepage": "https://etherparty.io" - }, - "marketcap_usd": 265967, - "name": "Etherparty FUEL", - "network": "eth", - "shortcut": "FUEL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FUN": { - "address": "0x419D0d8BdD9aF5e606Ae2232ed285Aff190E711b", - "links": { - "Homepage": "https://funfair.io" - }, - "marketcap_usd": 77061620, - "name": "Funfair", - "network": "eth", - "shortcut": "FUN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FXT": { - "address": "0x1829aA045E21E0D59580024A951DB48096e01782", - "links": { - "Homepage": "https://fuzex.co" - }, - "marketcap_usd": 0, - "name": "FuzeX", - "network": "eth", - "shortcut": "FXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FXY": { - "address": "0xA024E8057EEC474a9b2356833707Dd0579E26eF3", - "links": { - "Github": "https://github.com/fixynetwork/FIXY-NETWORK", - "Homepage": "https://fixyapp.io" - }, - "marketcap_usd": 0, - "name": "$FIXY NETWORK", - "network": "eth", - "shortcut": "FXY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FYN": { - "address": "0x88FCFBc22C6d3dBaa25aF478C578978339BDe77a", - "links": { - "Homepage": "http://www.fundyourselfnow.com" - }, - "marketcap_usd": 0, - "name": "Fund Yourself Now", - "network": "eth", - "shortcut": "FYN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FYP": { - "address": "0x8F0921f30555624143d427b340b1156914882C10", - "links": { - "Homepage": "https://flyp.me" - }, - "marketcap_usd": 618522, - "name": "FlypMe", - "network": "eth", - "shortcut": "FYP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:FYZ": { - "address": "0x6BFf2fE249601ed0Db3a87424a2E923118BB0312", - "links": { - "Homepage": "https://www.fyooz.io/" - }, - "marketcap_usd": 0, - "name": "Fyooz", - "network": "eth", - "shortcut": "FYZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:Fzcoin": { - "address": "0xE5aeE163513119F4F750376C718766B40fA37A5F", - "links": { - "Github": "https://github.com/fzcoinProtocol", - "Homepage": "https://fzcoin.cc/" - }, - "marketcap_usd": 0, - "name": "Frozencoin Network", - "network": "eth", - "shortcut": "Fzcoin", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:G-CRE": { - "address": "0xa3EE21C306A700E682AbCdfe9BaA6A08F3820419", - "links": { - "Github": "https://github.com/gluwa/Creditcoin", - "Homepage": "https://creditcoinfoundation.org" - }, - "marketcap_usd": 103231356, - "name": "Creditcoin Token", - "network": "eth", - "shortcut": "G-CRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GAM": { - "address": "0xF67451Dc8421F0e0afEB52faa8101034ed081Ed9", - "links": { - "Github": "https://github.com/BlockchainLabsNZ/gambit", - "Homepage": "http://gambitcrypto.com" - }, - "marketcap_usd": 0, - "name": "Gambit", - "network": "eth", - "shortcut": "GAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GAME": { - "address": "0x63f88A2298a5c4AEE3c216Aa6D926B184a4b2437", - "links": { - "Github": "https://github.com/gamecredits-project", - "Homepage": "https://www.gamecredits.org" - }, - "marketcap_usd": 3159640, - "name": "GAME Credits", - "network": "eth", - "shortcut": "GAME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GAT": { - "address": "0x687174f8C49ceb7729D925C3A961507ea4Ac7b28", - "links": { - "Homepage": "https://www.gatcoin.io" - }, - "marketcap_usd": 0, - "name": "Global Awards Token", - "network": "eth", - "shortcut": "GAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GATE": { - "address": "0x9d7630aDF7ab0b0CB00Af747Db76864df0EC82E4", - "links": { - "Github": "https://github.com/GateNet-IO/gate-erc20-token", - "Homepage": "https://gatetoken.io/" - }, - "marketcap_usd": 0, - "name": "GATE Token", - "network": "eth", - "shortcut": "GATE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GAVEL": { - "address": "0x708876f486e448Ee89eB332bFbC8E593553058b9", - "links": { - "Homepage": "http://gavelcoin.com" - }, - "marketcap_usd": 0, - "name": "GAVEL", - "network": "eth", - "shortcut": "GAVEL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GBO": { - "address": "0xCc2a74b28E786Fac86bE3CA354B1941c25aB3EaB", - "links": { - "Github": "https://github.com/GABOtoken", - "Homepage": "http://gabotoken.org" - }, - "marketcap_usd": 0, - "name": "GABO", - "network": "eth", - "shortcut": "GBO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GBT": { - "address": "0x7585F835ae2d522722d2684323a0ba83401f32f5", - "links": { - "Github": "https://github.com/myHelloGold/Foundation", - "Homepage": "https://www.hellogold.org" - }, - "marketcap_usd": 0, - "name": "GBT", - "network": "eth", - "shortcut": "GBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GBX": { - "address": "0x12fCd6463E66974cF7bBC24FFC4d40d6bE458283", - "links": { - "Homepage": "https://www.globitexico.com" - }, - "marketcap_usd": 0, - "name": "Globitex", - "network": "eth", - "shortcut": "GBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GC": { - "address": "0x8Eb38715604b938812DEC25A0A1bc05B4becB9ca", - "links": { - "Github": "https://github.com/Gric-Coin", - "Homepage": "https://agric.io" - }, - "marketcap_usd": 0, - "name": "Gric Coin", - "network": "eth", - "shortcut": "GC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GCG": { - "address": "0x1778fFfBD431be2AC3D69e64d1d819C786B2BEe0", - "links": { - "Homepage": "https://globalcryptogate.com/" - }, - "marketcap_usd": 0, - "name": "Global Crypto Gate", - "network": "eth", - "shortcut": "GCG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GCP": { - "address": "0xdb0F69306FF8F949f258E83f6b87ee5D052d0b23", - "links": { - "Github": "https://github.com/Globcoin", - "Homepage": "https://globcoin.io/" - }, - "marketcap_usd": 0, - "name": "Globcoin Crypto Platform", - "network": "eth", - "shortcut": "GCP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GCU": { - "address": "0xa4ec83c8907888d006A37debF755ee39766f38ae", - "links": { - "Homepage": "http://glpt.io/" - }, - "marketcap_usd": 0, - "name": "Global Currency Unit", - "network": "eth", - "shortcut": "GCU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GCX": { - "address": "0x44A67C8570a61A28bAfd0035042f2F0A73a64428", - "links": { - "Github": "https://github.com/engenie/GermanCoin_GCX", - "Homepage": "https://www.germancoin.info" - }, - "marketcap_usd": 0, - "name": "GermanCoin", - "network": "eth", - "shortcut": "GCX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GDAO": { - "address": "0x515d7E9D75E2b76DB60F8a051Cd890eBa23286Bc", - "links": { - "Github": "https://github.com/Governor-DAO", - "Homepage": "https://www.governordao.org" - }, - "marketcap_usd": 362122, - "name": "Governor DAO", - "network": "eth", - "shortcut": "GDAO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GEE": { - "address": "0x4F4f0Db4de903B88f2B1a2847971E231D54F8fd3", - "links": { - "Github": "https://github.com/GeensNPO", - "Homepage": "https://www.geens.com" - }, - "marketcap_usd": 0, - "name": "Geens NPO", - "network": "eth", - "shortcut": "GEE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GEFT": { - "address": "0xd0464A1985edB76Ba82602534a2d89d8cCf3B7Ec", - "links": { - "Github": "https://github.com/GlobalEducationFoundation", - "Homepage": "https://globaledufoundation.org" - }, - "marketcap_usd": 0, - "name": "GlobalEdu", - "network": "eth", - "shortcut": "GEFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GELD": { - "address": "0x24083Bb30072643C3bB90B44B7285860a755e687", - "links": { - "Homepage": "https://www.soerengelder.com" - }, - "marketcap_usd": 0, - "name": "GELD", - "network": "eth", - "shortcut": "GELD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GEM": { - "address": "0xc7BbA5b765581eFb2Cdd2679DB5Bea9eE79b201f", - "links": { - "Homepage": "https://gems.org" - }, - "marketcap_usd": 94104, - "name": "Gems", - "network": "eth", - "shortcut": "GEM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GEN": { - "address": "0x543Ff227F64Aa17eA132Bf9886cAb5DB55DCAddf", - "links": { - "Github": "https://github.com/daostack", - "Homepage": "https://daostack.io" - }, - "marketcap_usd": 1374362, - "name": "DAOstack", - "network": "eth", - "shortcut": "GEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GENE": { - "address": "0x6DD4e4Aad29A40eDd6A409b9c1625186C9855b4D", - "links": { - "Homepage": "https://parkgene.io" - }, - "marketcap_usd": 0, - "name": "Parkgene", - "network": "eth", - "shortcut": "GENE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GET": { - "address": "0x8a854288a5976036A725879164Ca3e91d30c6A1B", - "links": { - "Github": "https://github.com/Getprotocol", - "Homepage": "http://www.get-protocol.io" - }, - "marketcap_usd": 17570214, - "name": "GET Protocol", - "network": "eth", - "shortcut": "GET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GFN": { - "address": "0x3930E4dDb4d24ef2F4CB54C1f009a3694b708428", - "links": { - "Github": "https://github.com/GameFanz/GFN", - "Homepage": "https://gamefanz.io/" - }, - "marketcap_usd": 0, - "name": "GameFanz", - "network": "eth", - "shortcut": "GFN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GGC": { - "address": "0x7F969C4D388Ca0AE39A4FdDB1A6f89878CA2fBf8", - "links": { - "Homepage": "https://ico.gg.international" - }, - "marketcap_usd": 0, - "name": "GGCOIN", - "network": "eth", - "shortcut": "GGC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GHX": { - "address": "0x728f30fa2f100742C7949D1961804FA8E0B1387d", - "links": { - "Homepage": "https://gamerhash.io/" - }, - "marketcap_usd": 5973218, - "name": "GamerCoin", - "network": "eth", - "shortcut": "GHX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GIF": { - "address": "0xFcD862985628b254061F7A918035B80340D045d3", - "links": { - "Homepage": "https://gifcoin.io/" - }, - "marketcap_usd": 0, - "name": "GIFcoin Token", - "network": "eth", - "shortcut": "GIF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GIM": { - "address": "0xaE4f56F072c34C0a65B3ae3E4DB797D831439D93", - "links": { - "Github": "https://github.com/thegimliproject/GimliToken", - "Homepage": "https://gimli.io" - }, - "marketcap_usd": 0, - "name": "Gimli", - "network": "eth", - "shortcut": "GIM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GIRL": { - "address": "0x9Aa7d119bdf77F65A7284581A211D8c44ffb04b4", - "links": { - "Github": "https://github.com/women-finance", - "Homepage": "https://womensmoneynetwork.com" - }, - "marketcap_usd": 0, - "name": "Girl Coin", - "network": "eth", - "shortcut": "GIRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GIV": { - "address": "0x900dB999074d9277c5DA2A43F252D74366230DA0", - "links": { - "Github": "https://github.com/Giveth", - "Homepage": "https://giveth.io/" - }, - "marketcap_usd": 0, - "name": "Giveth", - "network": "eth", - "shortcut": "GIV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GL": { - "address": "0xA5B399a76bbAbEf93D70255525C1d2BCC3701d0b", - "links": { - "Github": "https://github.com/glosmatin/GLOSMATIN", - "Homepage": "https://glosmatin.com/" - }, - "marketcap_usd": 0, - "name": "GLOSMATIN", - "network": "eth", - "shortcut": "GL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GLA": { - "address": "0x71D01dB8d6a2fBEa7f8d434599C237980C234e4C", - "links": { - "Homepage": "https://gladius.io" - }, - "marketcap_usd": 0, - "name": "Gladius", - "network": "eth", - "shortcut": "GLA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GMB": { - "address": "0xA0008F510fE9eE696E7E320C9e5cbf61E27791Ee", - "links": { - "Homepage": "https://gamb.io" - }, - "marketcap_usd": 1277478, - "name": "GAMB", - "network": "eth", - "shortcut": "GMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GNO": { - "address": "0x6810e776880C02933D47DB1b9fc05908e5386b96", - "links": { - "Homepage": "https://gnosis.pm" - }, - "marketcap_usd": 278912676, - "name": "Gnosis", - "network": "eth", - "shortcut": "GNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GNT": { - "address": "0xa74476443119A942dE498590Fe1f2454d7D4aC0d", - "links": { - "Github": "https://github.com/golemfactory/golem", - "Homepage": "https://golem.network" - }, - "marketcap_usd": 0, - "name": "Golem", - "network": "eth", - "shortcut": "GNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GNX": { - "address": "0x6EC8a24CaBdc339A06a172F8223ea557055aDAa5", - "links": { - "Homepage": "https://genaro.network" - }, - "marketcap_usd": 1942086, - "name": "Genaro Network", - "network": "eth", - "shortcut": "GNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GNY": { - "address": "0x247551F2EB3362E222c742E9c788B8957D9BC87e", - "links": { - "Github": "https://github.com/GNYIO", - "Homepage": "https://www.gny.io/" - }, - "marketcap_usd": 0, - "name": "GNY", - "network": "eth", - "shortcut": "GNY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GOLDX": { - "address": "0xeAb43193CF0623073Ca89DB9B712796356FA7414", - "links": { - "Github": "https://github.com/myHelloGold/Foundation", - "Homepage": "https://www.hellogold.org/" - }, - "marketcap_usd": 0, - "name": "GOLDX", - "network": "eth", - "shortcut": "GOLDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GOT": { - "address": "0x423b5F62b328D0D6D44870F4Eee316befA0b2dF5", - "links": { - "Homepage": "https://gonetwork.co/index.html" - }, - "marketcap_usd": 0, - "name": "GoNetwork", - "network": "eth", - "shortcut": "GOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GOVI": { - "address": "0xeEAA40B28A2d1b0B08f6f97bB1DD4B75316c6107", - "links": { - "Github": "https://github.com/coti-io/cvi-contracts", - "Homepage": "https://cvi.finance" - }, - "marketcap_usd": 9674350, - "name": "GOVI", - "network": "eth", - "shortcut": "GOVI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GR": { - "address": "0xcE593a29905951E8Fc579bC092ecA72577dA575c", - "links": { - "Homepage": "https://cryptochief.net" - }, - "marketcap_usd": 0, - "name": "GROM", - "network": "eth", - "shortcut": "GR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GRID": { - "address": "0x12B19D3e2ccc14Da04FAe33e63652ce469b3F2FD", - "links": { - "Homepage": "http://gridplus.io" - }, - "marketcap_usd": 8168623, - "name": "Grid+", - "network": "eth", - "shortcut": "GRID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GRMD": { - "address": "0xb444208cB0516C150178fCf9a52604BC04A1aCEa", - "links": { - "Homepage": "https://www.greenmed.io" - }, - "marketcap_usd": 0, - "name": "GreenMed", - "network": "eth", - "shortcut": "GRMD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GROO": { - "address": "0xC17195bde49D70CefCF8A9F2ee1759FFC27BF0B1", - "links": { - "Github": "https://github.com/groocoindev", - "Homepage": "https://groo.io/" - }, - "marketcap_usd": 0, - "name": "Groocoin", - "network": "eth", - "shortcut": "GROO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GROW": { - "address": "0x0a9A9ce600D08BF9b76F49FA4e7b38A67EBEB1E6", - "links": { - "Github": "https://github.com/growchainnet", - "Homepage": "http://www.growchain.us" - }, - "marketcap_usd": 0, - "name": "Growchain", - "network": "eth", - "shortcut": "GROW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GRT": { - "address": "0xc944E90C64B2c07662A292be6244BDf05Cda44a7", - "links": { - "Github": "https://github.com/graphprotocol", - "Homepage": "https://thegraph.com" - }, - "marketcap_usd": 1397892462, - "name": "Graph Token", - "network": "eth", - "shortcut": "GRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GSC": { - "address": "0x228ba514309FFDF03A81a205a6D040E429d6E80C", - "links": { - "Homepage": "https://www.gsc.social" - }, - "marketcap_usd": 1307261, - "name": "Global Social Chain", - "network": "eth", - "shortcut": "GSC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GSE": { - "address": "0xe530441f4f73bDB6DC2fA5aF7c3fC5fD551Ec838", - "links": { - "Homepage": "https://gse.network" - }, - "marketcap_usd": 0, - "name": "GSENetwork", - "network": "eth", - "shortcut": "GSE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GTC": { - "address": "0xB70835D7822eBB9426B56543E391846C107bd32C", - "links": { - "Github": "https://github.com/GameLeLe", - "Homepage": "https://game.com" - }, - "marketcap_usd": 626409, - "name": "GTC Token", - "network": "eth", - "shortcut": "GTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GTEC": { - "address": "0x30E193bd3F52713D5562cf316f35115034525f44", - "links": { - "Github": "https://github.com/Sustainability-Creative-Co/GreenTechCoin", - "Homepage": "https://greentechcoin.xyz" - }, - "marketcap_usd": 0, - "name": "Green Tech Coin", - "network": "eth", - "shortcut": "GTEC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GTH": { - "address": "0xeb986DA994E4a118d5956b02d8b7c3C7CE373674", - "links": { - "Github": "https://github.com/GatherNetwork", - "Homepage": "https://gather.network" - }, - "marketcap_usd": 1331693, - "name": "GTH", - "network": "eth", - "shortcut": "GTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GTKT": { - "address": "0x025abAD9e518516fdaAFBDcdB9701b37fb7eF0FA", - "links": { - "Github": "https://github.com/sprux/BackToEarth", - "Homepage": "https://backto.earth" - }, - "marketcap_usd": 0, - "name": "GTKT", - "network": "eth", - "shortcut": "GTKT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GTO": { - "address": "0xC5bBaE50781Be1669306b9e001EFF57a2957b09d", - "links": { - "Github": "https://github.com/GIFTO-io", - "Homepage": "https://gifto.io/" - }, - "marketcap_usd": 0, - "name": "Gifto", - "network": "eth", - "shortcut": "GTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GUESS": { - "address": "0xBDCFbf5C4D91Abc0bC9709C7286d00063c0e6F22", - "links": { - "Homepage": "https://peerguess.com" - }, - "marketcap_usd": 0, - "name": "Peerguess", - "network": "eth", - "shortcut": "GUESS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GULD": { - "address": "0x9847345de8b614c956146bbea549336d9C8d26b6", - "links": { - "Github": "https://github.com/guldcoin", - "Homepage": "https://guld.io" - }, - "marketcap_usd": 0, - "name": "GULD ERC20", - "network": "eth", - "shortcut": "GULD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GUP": { - "address": "0xf7B098298f7C69Fc14610bf71d5e02c60792894C", - "links": { - "Homepage": "https://matchpool.co" - }, - "marketcap_usd": 0, - "name": "Matchpool", - "network": "eth", - "shortcut": "GUP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GVT": { - "address": "0x103c3A209da59d3E7C4A89307e66521e081CFDF0", - "links": { - "Github": "https://github.com/GenesisVision", - "Homepage": "https://genesis.vision" - }, - "marketcap_usd": 849673, - "name": "Genesis Vision", - "network": "eth", - "shortcut": "GVT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GXC": { - "address": "0x58ca3065C0F24C7c96Aee8d6056b5B5deCf9c2f8", - "links": { - "Homepage": "https://genevieveco.com" - }, - "marketcap_usd": 0, - "name": "GXC", - "network": "eth", - "shortcut": "GXC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GXVC": { - "address": "0x22F0AF8D78851b72EE799e05F54A77001586B18A", - "links": { - "Github": "https://github.com/GxC17Genevieve/GXVC", - "Homepage": "https://genevieveco.io" - }, - "marketcap_usd": 0, - "name": "Genevieve VC", - "network": "eth", - "shortcut": "GXVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GZB": { - "address": "0x9DAe8b7F6D37ea8e5d32C6c3E856a6d8a1d3B363", - "links": { - "Github": "https://github.com/Gigzi", - "Homepage": "https://gigzi.com" - }, - "marketcap_usd": 0, - "name": "GigziBlack", - "network": "eth", - "shortcut": "GZB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GZE": { - "address": "0x8C65e992297d5f092A756dEf24F4781a280198Ff", - "links": { - "Homepage": "https://gazecoin.io" - }, - "marketcap_usd": 0, - "name": "GazeCoin", - "network": "eth", - "shortcut": "GZE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GZM": { - "address": "0x0A680E503fd9ae14B62444C75ffB4BEf1F105666", - "links": { - "Github": "https://github.com/dimabarsu/GZM-Armacoin/blob/master/armacoin.sol", - "Homepage": "https://armacoin.info" - }, - "marketcap_usd": 0, - "name": "Arma Coin", - "network": "eth", - "shortcut": "GZM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:GZR": { - "address": "0xE638dc39b6aDBEE8526b5C22380b4b45dAf46d8e", - "links": { - "Github": "https://github.com/GizerInc/Gizer", - "Homepage": "https://gizer.io" - }, - "marketcap_usd": 0, - "name": "Gizer", - "network": "eth", - "shortcut": "GZR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HABS": { - "address": "0x5bfc1FF7f9e087C64fEfb34F2e7cF24e5570919F", - "links": { - "Homepage": "https://habitus.global/" - }, - "marketcap_usd": 0, - "name": "Habitus ", - "network": "eth", - "shortcut": "HABS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HAK": { - "address": "0x93a7174dafd31d13400cD9fa01f4e5B5BAa00D39", - "links": { - "Github": "https://github.com/friendsfingers", - "Homepage": "https://www.friendsfingers.com" - }, - "marketcap_usd": 0, - "name": "Shaka", - "network": "eth", - "shortcut": "HAK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HAND": { - "address": "0x48C1B2f3eFA85fbafb2ab951bF4Ba860a08cdBB7", - "links": { - "Homepage": "https://www.showhand.io" - }, - "marketcap_usd": 1007382, - "name": "ShowHand", - "network": "eth", - "shortcut": "HAND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HAPPY": { - "address": "0x5A567e28dbFa2bBD3ef13C0a01be114745349657", - "links": { - "Homepage": "https://btr.works" - }, - "marketcap_usd": 0, - "name": "Happiness", - "network": "eth", - "shortcut": "HAPPY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HAREM": { - "address": "0x2B89D32CfB9b28DFCc7FAcC22453c812F9097655", - "links": { - "Homepage": "https://harem-token.com/" - }, - "marketcap_usd": 0, - "name": "Harem Token", - "network": "eth", - "shortcut": "HAREM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HAT": { - "address": "0x9002D4485b7594e3E850F0a206713B305113f69e", - "links": { - "Homepage": "https://www.hawala.today/" - }, - "marketcap_usd": 0, - "name": "Hawala Today", - "network": "eth", - "shortcut": "HAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HB": { - "address": "0xE2492F8D2A2618d8709Ca99b1d8d75713Bd84089", - "links": { - "Homepage": "https://heartbout.com" - }, - "marketcap_usd": 11910, - "name": "HeartBout", - "network": "eth", - "shortcut": "HB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HBT": { - "address": "0xDd6C68bb32462e01705011a4e2Ad1a60740f217F", - "links": { - "Homepage": "https://www.hubii.network" - }, - "marketcap_usd": 0, - "name": "Hubii Network", - "network": "eth", - "shortcut": "HBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HBZ": { - "address": "0xE34e1944E776f39B9252790a0527eBDa647aE668", - "links": { - "Homepage": "https://www.hbzcoin.com/#" - }, - "marketcap_usd": 0, - "name": "HBZ coin", - "network": "eth", - "shortcut": "HBZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HDG": { - "address": "0xfFe8196bc259E8dEDc544d935786Aa4709eC3E64", - "links": { - "Homepage": "https://www.hedge-crypto.com" - }, - "marketcap_usd": 0, - "name": "Hedge Crypto", - "network": "eth", - "shortcut": "HDG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HDLRE": { - "address": "0x86a63063b3a60652FB070F23Cbb4A9833FDBBFF8", - "links": { - "Github": "https://github.com/HodlerCompany", - "Homepage": "https://hodler.energy" - }, - "marketcap_usd": 0, - "name": "Hodler Mining", - "network": "eth", - "shortcut": "HDLRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HEM": { - "address": "0x19747816A030fECDa3394C6062CDF6b9B4dB0E0b", - "links": { - "Github": "https://github.com/Hemelios/hemelios-token", - "Homepage": "https://www.hemelios.io" - }, - "marketcap_usd": 0, - "name": "Hemelios", - "network": "eth", - "shortcut": "HEM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HER": { - "address": "0x491C9A23DB85623EEd455a8EfDd6AbA9b911C5dF", - "links": { - "Homepage": "https://heronode.io" - }, - "marketcap_usd": 0, - "name": "HeroNode", - "network": "eth", - "shortcut": "HER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HEX:2b59": { - "address": "0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39", - "links": { - "Github": "https://github.com/bitcoinHEX", - "Homepage": "https://hex.win" - }, - "marketcap_usd": 10933582176, - "name": "HEX", - "network": "eth", - "shortcut": "HEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HEY": { - "address": "0xe9C9e7E1DaBea830C958C39D6b25964a6F52143A", - "links": { - "Github": "https://github.com/hey-network", - "Homepage": "https://hey.network" - }, - "marketcap_usd": 0, - "name": "HeyToken", - "network": "eth", - "shortcut": "HEY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HGT": { - "address": "0xba2184520A1cC49a6159c57e61E1844E085615B6", - "links": { - "Github": "https://github.com/myHelloGold/Foundation", - "Homepage": "https://www.hellogold.org" - }, - "marketcap_usd": 0, - "name": "HelloGold", - "network": "eth", - "shortcut": "HGT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HIBT": { - "address": "0x9bb1Db1445b83213a56d90d331894b3f26218e4e", - "links": { - "Homepage": "https://www.hibtc.com/" - }, - "marketcap_usd": 0, - "name": "HiBTC Token", - "network": "eth", - "shortcut": "HIBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HIG": { - "address": "0xa9240fBCAC1F0b9A6aDfB04a53c8E3B0cC1D1444", - "links": { - "Github": "https://github.com/ethereumhigh/Ethereum-High", - "Homepage": "https://www.ethereumhigh.org/" - }, - "marketcap_usd": 0, - "name": "ethereumhigh", - "network": "eth", - "shortcut": "HIG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HIN": { - "address": "0x7FCcaDee21660425FDEc86029b6362845ffC052C", - "links": { - "Homepage": "https://tokens.rebene.com" - }, - "marketcap_usd": 0, - "name": "TimeBanking", - "network": "eth", - "shortcut": "HIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HKG": { - "address": "0x14F37B574242D366558dB61f3335289a5035c506", - "links": { - "Homepage": "http://www.ether.camp" - }, - "marketcap_usd": 0, - "name": "HKG", - "network": "eth", - "shortcut": "HKG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HKN": { - "address": "0x9e6B2B11542f2BC52f3029077acE37E8fD838D7F", - "links": { - "Homepage": "https://hacken.io" - }, - "marketcap_usd": 0, - "name": "Hacken", - "network": "eth", - "shortcut": "HKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HKY": { - "address": "0x88aC94D5d175130347Fc95E109d77AC09dbF5ab7", - "links": { - "Github": "https://github.com/HickyToken/hickycontracts", - "Homepage": "https://hicky.io" - }, - "marketcap_usd": 0, - "name": "Hicky", - "network": "eth", - "shortcut": "HKY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HLX": { - "address": "0x66eb65D7Ab8e9567ba0fa6E37c305956c5341574", - "links": { - "Homepage": "https://helex.world" - }, - "marketcap_usd": 0, - "name": "Helex", - "network": "eth", - "shortcut": "HLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HMQ": { - "address": "0xcbCC0F036ED4788F63FC0fEE32873d6A7487b908", - "links": { - "Homepage": "https://humaniq.com" - }, - "marketcap_usd": 774910, - "name": "Humaniq", - "network": "eth", - "shortcut": "HMQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HNI": { - "address": "0xD6Cb175719365a2ea630f266C53dDfBe4e468e25", - "links": { - "Homepage": "https://hunibit.com" - }, - "marketcap_usd": 0, - "name": "Hunimal Token", - "network": "eth", - "shortcut": "HNI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HNST": { - "address": "0x9C9Fe3bD60b22A9735908B9589011E78F2025C11", - "links": { - "Github": "https://github.com/honestmining", - "Homepage": "https://honestmining.com" - }, - "marketcap_usd": 0, - "name": "Honest", - "network": "eth", - "shortcut": "HNST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HODL": { - "address": "0xb45d7Bc4cEBcAB98aD09BABDF8C818B2292B672c", - "links": { - "Homepage": "https://github.com/arachnid/hodlcoin" - }, - "marketcap_usd": 0, - "name": "HODLCoin", - "network": "eth", - "shortcut": "HODL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HORSE": { - "address": "0x5B0751713b2527d7f002c0c4e2a37e1219610A6B", - "links": { - "Github": "https://github.com/ethorse", - "Homepage": "https://ethorse.com" - }, - "marketcap_usd": 0, - "name": "Ethorse", - "network": "eth", - "shortcut": "HORSE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HOT (Holo)": { - "address": "0x6c6EE5e31d828De241282B9606C8e98Ea48526E2", - "links": { - "Github": "https://github.com/Holo-Host", - "Homepage": "https://holo.host/" - }, - "marketcap_usd": 357796049, - "name": "Holo Token", - "network": "eth", - "shortcut": "HOT (Holo)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HOT (Hydro)": { - "address": "0x9AF839687F6C94542ac5ece2e317dAAE355493A1", - "links": { - "Homepage": "https://thehydrofoundation.com/" - }, - "marketcap_usd": 2858970, - "name": "Hydro Protocol", - "network": "eth", - "shortcut": "HOT (Hydro)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HST": { - "address": "0x554C20B7c486beeE439277b4540A434566dC4C02", - "links": { - "Homepage": "https://horizonstate.com" - }, - "marketcap_usd": 0, - "name": "Decision Token", - "network": "eth", - "shortcut": "HST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HT": { - "address": "0x6f259637dcD74C767781E37Bc6133cd6A68aa161", - "links": { - "Homepage": "https://www.hbg.com" - }, - "marketcap_usd": 856172229, - "name": "Huobi Token", - "network": "eth", - "shortcut": "HT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HTX": { - "address": "0x46ae264Bf6d9Dc6Dd84c31064551f961c67a755c", - "links": { - "Homepage": "https://www.hotcrypto.org" - }, - "marketcap_usd": 0, - "name": "HOT", - "network": "eth", - "shortcut": "HTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HUB": { - "address": "0xba358B6f5b4c0215650444B8C30D870B55050D2D", - "links": { - "Github": "https://github.com/hubtoken", - "Homepage": "https://hubtoken.org/" - }, - "marketcap_usd": 0, - "name": "HubToken", - "network": "eth", - "shortcut": "HUB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HUBS": { - "address": "0x001Fc4a7f2f586596308091c7B296D4535A25a90", - "links": { - "Github": "https://github.com/hubscop", - "Homepage": "https://hubscop.com" - }, - "marketcap_usd": 0, - "name": "Hubscop", - "network": "eth", - "shortcut": "HUBS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HUR": { - "address": "0xCDB7eCFd3403Eef3882c65B761ef9B5054890a47", - "links": { - "Github": "https://github.com/HurifyPlatform", - "Homepage": "https://hurify.co/" - }, - "marketcap_usd": 0, - "name": "$Hurify Token", - "network": "eth", - "shortcut": "HUR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HV": { - "address": "0x141ABB03F001dEDED9A0223d4ff26d929117B72e", - "links": { - "Github": "https://github.com/HighVibe", - "Homepage": "https://www.highvibe.network/" - }, - "marketcap_usd": 0, - "name": "HighVibe", - "network": "eth", - "shortcut": "HV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HVN": { - "address": "0xC0Eb85285d83217CD7c891702bcbC0FC401E2D9D", - "links": { - "Github": "https://github.com/HiveProjectLTD", - "Homepage": "https://www.hiveterminal.com" - }, - "marketcap_usd": 479398, - "name": "Hiveterminal Token", - "network": "eth", - "shortcut": "HVN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:HYDRO": { - "address": "0xEBBdf302c940c6bfd49C6b165f457fdb324649bc", - "links": { - "Github": "https://github.com/hydrogen-dev", - "Homepage": "https://www.hydrogenplatform.com/hydro" - }, - "marketcap_usd": 0, - "name": "Hydro", - "network": "eth", - "shortcut": "HYDRO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IAD": { - "address": "0xC1E2097d788d33701BA3Cc2773BF67155ec93FC4", - "links": { - "Github": "https://github.com/IADOWR", - "Homepage": "https://www.iadowrcoin.com" - }, - "marketcap_usd": 0, - "name": "IADOWR Coin", - "network": "eth", - "shortcut": "IAD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ICD": { - "address": "0x3c20d67b6B1aE0985F913aBb7397babc2fBb1A1F", - "links": { - "Github": "https://github.com/ICEDIUM", - "Homepage": "https://icedium.com" - }, - "marketcap_usd": 0, - "name": "ICEDIUM", - "network": "eth", - "shortcut": "ICD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ICE": { - "address": "0x5a84969bb663fb64F6d015DcF9F622Aedc796750", - "links": { - "Homepage": "https://idice.io" - }, - "marketcap_usd": 0, - "name": "ICE", - "network": "eth", - "shortcut": "ICE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ICN": { - "address": "0x888666CA69E0f178DED6D75b5726Cee99A87D698", - "links": { - "Homepage": "https://www.iconomi.net" - }, - "marketcap_usd": 0, - "name": "ICONOMI", - "network": "eth", - "shortcut": "ICN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ICO": { - "address": "0xa33e729bf4fdeb868B534e1f20523463D9C46bEe", - "links": { - "Homepage": "http://icocoin.org" - }, - "marketcap_usd": 0, - "name": "ICO", - "network": "eth", - "shortcut": "ICO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ICOS": { - "address": "0x014B50466590340D41307Cc54DCee990c8D58aa8", - "links": { - "Homepage": "https://icos.icobox.io" - }, - "marketcap_usd": 0, - "name": "ICOS", - "network": "eth", - "shortcut": "ICOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ID": { - "address": "0xEBd9D99A3982d547C5Bb4DB7E3b1F9F14b67Eb83", - "links": { - "Homepage": "https://www.everest.org" - }, - "marketcap_usd": 4268877, - "name": "Everest (ID)", - "network": "eth", - "shortcut": "ID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IDEA": { - "address": "0x814CAfd4782d2e728170FDA68257983F03321c58", - "links": { - "Homepage": "http://www.ideatoken.io/" - }, - "marketcap_usd": 0, - "name": "IDEA Token", - "network": "eth", - "shortcut": "IDEA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IDH": { - "address": "0x5136C98A80811C3f46bDda8B5c4555CFd9f812F0", - "links": { - "Homepage": "https://indahash.com" - }, - "marketcap_usd": 0, - "name": "indaHash", - "network": "eth", - "shortcut": "IDH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IDRT": { - "address": "0x998FFE1E43fAcffb941dc337dD0468d52bA5b48A", - "links": { - "Github": "https://github.com/rupiah-token/", - "Homepage": "https://www.rupiahtoken.com" - }, - "marketcap_usd": 7924738, - "name": "Rupiah Token", - "network": "eth", - "shortcut": "IDRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IFT": { - "address": "0x7654915A1b82D6D2D0AFc37c52Af556eA8983c7E", - "links": { - "Homepage": "https://investfeed.com" - }, - "marketcap_usd": 134220, - "name": "InvestFeed", - "network": "eth", - "shortcut": "IFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IG": { - "address": "0x8a88f04e0c905054D2F33b26BB3A46D7091A039A", - "links": { - "Homepage": "http://igtoken.net" - }, - "marketcap_usd": 69787, - "name": "IGToken", - "network": "eth", - "shortcut": "IG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IGI": { - "address": "0x449c640B6C7fce4f8aD2e3Dcd900D13be40174Af", - "links": { - "Github": "https://github.com/igicoin/IGI", - "Homepage": "https://igicoin.com" - }, - "marketcap_usd": 0, - "name": "IGICOIN", - "network": "eth", - "shortcut": "IGI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IHT": { - "address": "0xEda8B016efA8b1161208Cf041cD86972eeE0F31E", - "links": { - "Homepage": "https://ihtcoin.com" - }, - "marketcap_usd": 159461, - "name": "I HOUSE TOKEN", - "network": "eth", - "shortcut": "IHT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IIC": { - "address": "0x16662F73dF3e79e54c6c5938b4313f92C524C120", - "links": { - "Homepage": "https://ibiscoin.co" - }, - "marketcap_usd": 0, - "name": "IIC", - "network": "eth", - "shortcut": "IIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IKB": { - "address": "0x88AE96845e157558ef59e9Ff90E766E22E480390", - "links": { - "Github": "https://github.com/mitchellfchan/IKB", - "Homepage": "http://www.mitchellfchan.com" - }, - "marketcap_usd": 0, - "name": "IKB", - "network": "eth", - "shortcut": "IKB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IMC": { - "address": "0xe3831c5A982B279A198456D577cfb90424cb6340", - "links": { - "Homepage": "http://immunecoin.info" - }, - "marketcap_usd": 0, - "name": "Immune Coin", - "network": "eth", - "shortcut": "IMC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IND": { - "address": "0xf8e386EDa857484f5a12e4B5DAa9984E06E73705", - "links": { - "Homepage": "https://indorse.io" - }, - "marketcap_usd": 148825, - "name": "Indorse", - "network": "eth", - "shortcut": "IND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INF": { - "address": "0x00E150D741Eda1d49d341189CAE4c08a73a49C95", - "links": { - "Github": "https://github.com/InfinitusToken/InfinitusToken", - "Homepage": "https://inftech.io/ " - }, - "marketcap_usd": 0, - "name": "InfinitusTokens", - "network": "eth", - "shortcut": "INF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ING": { - "address": "0x24dDFf6D8B8a42d835af3b440De91f3386554Aa4", - "links": { - "Homepage": "https://iungo.network" - }, - "marketcap_usd": 0, - "name": "Iungo", - "network": "eth", - "shortcut": "ING", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INS": { - "address": "0x5B2e4a700dfBc560061e957edec8F6EeEb74a320", - "links": { - "Homepage": "https://insolar.io" - }, - "marketcap_usd": 0, - "name": "Insolar", - "network": "eth", - "shortcut": "INS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INSTAR": { - "address": "0xc72fe8e3Dd5BeF0F9f31f259399F301272eF2a2D", - "links": { - "Homepage": "https://insights.network" - }, - "marketcap_usd": 0, - "name": "Insights Network", - "network": "eth", - "shortcut": "INSTAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INT": { - "address": "0x0b76544F6C413a555F309Bf76260d1E02377c02A", - "links": { - "Homepage": "https://intchain.io" - }, - "marketcap_usd": 0, - "name": "Internet Node Token", - "network": "eth", - "shortcut": "INT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INX": { - "address": "0x018d7D179350f1Bb9853D04982820E37ccE13a92", - "links": { - "Github": "https://github.com/InMax-Exchange", - "Homepage": "https://inmax.live/ " - }, - "marketcap_usd": 0, - "name": "Token INMAX", - "network": "eth", - "shortcut": "INX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:INXT": { - "address": "0xa8006C4ca56F24d6836727D106349320dB7fEF82", - "links": { - "Github": "https://github.com/Internxt/", - "Homepage": "https://internxt.com/" - }, - "marketcap_usd": 0, - "name": "Internxt", - "network": "eth", - "shortcut": "INXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IOST": { - "address": "0xFA1a856Cfa3409CFa145Fa4e20Eb270dF3EB21ab", - "links": { - "Homepage": "https://iost.io/" - }, - "marketcap_usd": 0, - "name": "IOSToken", - "network": "eth", - "shortcut": "IOST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IOTX": { - "address": "0x6fB3e0A217407EFFf7Ca062D46c26E5d60a14d69", - "links": { - "Github": "https://github.com/iotexproject/iotex-core", - "Homepage": "http://iotex.io/" - }, - "marketcap_usd": 264394884, - "name": "IoTeX Network", - "network": "eth", - "shortcut": "IOTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IPL": { - "address": "0x64CdF819d3E75Ac8eC217B3496d7cE167Be42e80", - "links": { - "Github": "https://github.com/InsurePal", - "Homepage": "https://insurepal.io/" - }, - "marketcap_usd": 34625, - "name": "InsurePal token", - "network": "eth", - "shortcut": "IPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IPSX": { - "address": "0x001F0aA5dA15585e5b2305DbaB2bac425ea71007", - "links": { - "Homepage": "https://ip.sx" - }, - "marketcap_usd": 0, - "name": "IP Exchange", - "network": "eth", - "shortcut": "IPSX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IQN": { - "address": "0x0DB8D8b76BC361bAcbB72E2C491E06085A97Ab31", - "links": { - "Github": "https://github.com/iqeon", - "Homepage": "https://iqeon.io/" - }, - "marketcap_usd": 1731566, - "name": "IQeon", - "network": "eth", - "shortcut": "IQN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ISL": { - "address": "0x1969442391737025812C2215E77E676d7fA84847", - "links": { - "Github": "https://github.com/islamicbankcoin", - "Homepage": "http://islamicbankcoin.com" - }, - "marketcap_usd": 0, - "name": "Islamic Bank", - "network": "eth", - "shortcut": "ISL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IST34": { - "address": "0x0cF713b11C9b986EC40D65bD4F7fbd50F6ff2d64", - "links": { - "Github": "https://github.com/IST34Token", - "Homepage": "https://hiperteknoloji.org" - }, - "marketcap_usd": 0, - "name": "IST34 Token", - "network": "eth", - "shortcut": "IST34", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ITC": { - "address": "0x5E6b6d9aBAd9093fdc861Ea1600eBa1b355Cd940", - "links": { - "Github": "https://github.com/IoTChainCode", - "Homepage": "https://iotchain.io/" - }, - "marketcap_usd": 0, - "name": "IoT Chain", - "network": "eth", - "shortcut": "ITC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ITO": { - "address": "0x293B0Cd0991DB07c8529fEBb01bc7D052315C5Ab", - "links": { - "Github": "https://github.com/InTimeFoundation", - "Homepage": "https://www.intimefoundation.org" - }, - "marketcap_usd": 0, - "name": "InTime", - "network": "eth", - "shortcut": "ITO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ITR": { - "address": "0x6Ef5febbD2A56FAb23f18a69d3fB9F4E2A70440B", - "links": { - "Github": "http://github.com/Intercoin", - "Homepage": "https://intercoin.org" - }, - "marketcap_usd": 0, - "name": "Intercoin", - "network": "eth", - "shortcut": "ITR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ITT": { - "address": "0x0aeF06DcCCC531e581f0440059E6FfCC206039EE", - "links": { - "Github": "https://github.com/IntelligentTrading", - "Homepage": "http://intelligenttrading.org" - }, - "marketcap_usd": 0, - "name": "ITT Token", - "network": "eth", - "shortcut": "ITT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IVY": { - "address": "0xA4eA687A2A7F29cF2dc66B39c68e4411C0D00C49", - "links": { - "Homepage": "https://www.ivykoin.com" - }, - "marketcap_usd": 0, - "name": "IvyKoin Public Network Tokens", - "network": "eth", - "shortcut": "IVY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IXT": { - "address": "0xfcA47962D45ADFdfd1Ab2D972315dB4ce7CCf094", - "links": { - "Homepage": "https://www.insurex.co" - }, - "marketcap_usd": 60603, - "name": "InsureX", - "network": "eth", - "shortcut": "IXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:IoT": { - "address": "0xC34B21f6F8e51cC965c2393B3ccFa3b82BEb2403", - "links": { - "Homepage": "http://www.bitcoin-biz.net" - }, - "marketcap_usd": 0, - "name": "IoT\u30b3\u30a4\u30f3", - "network": "eth", - "shortcut": "IoT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:J8T": { - "address": "0x0D262e5dC4A06a0F1c90cE79C7a60C09DfC884E4", - "links": { - "Github": "https://github.com/jet8", - "Homepage": "https://jet8.io" - }, - "marketcap_usd": 0, - "name": "J8T Token", - "network": "eth", - "shortcut": "J8T", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JASMY": { - "address": "0x7420B4b9a0110cdC71fB720908340C03F9Bc03EC", - "links": { - "Github": "https://github.com/TokyoToken/JasmyCoin", - "Homepage": "https://jasmy.co.jp" - }, - "marketcap_usd": 285268503, - "name": "JasmyCoin", - "network": "eth", - "shortcut": "JASMY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JBD": { - "address": "0x9A3619499825fbAe63329Aa8bCb3f10CD5958E1c", - "links": { - "Homepage": "https://jubileedollar.com" - }, - "marketcap_usd": 0, - "name": "Jubilee Dollar", - "network": "eth", - "shortcut": "JBD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JBX": { - "address": "0x884e3902C4d5cFA86de4aCE7A96AA91EbC25C0Ff", - "links": { - "Homepage": "https://www.jboxcoin.org" - }, - "marketcap_usd": 0, - "name": "JBOX", - "network": "eth", - "shortcut": "JBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JC": { - "address": "0xE2D82Dc7dA0E6f882E96846451F4faBcc8f90528", - "links": { - "Homepage": "https://jesuscoin.network" - }, - "marketcap_usd": 0, - "name": "Jesus Coin", - "network": "eth", - "shortcut": "JC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JNT": { - "address": "0xa5Fd1A791C4dfcaacC963D4F73c6Ae5824149eA7", - "links": { - "Github": "https://github.com/jibrelnetwork", - "Homepage": "https://jibrel.network" - }, - "marketcap_usd": 0, - "name": "Jibrel Network", - "network": "eth", - "shortcut": "JNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JOB:dfbc": { - "address": "0xdfbc9050F5B01DF53512DCC39B4f2B2BBaCD517A", - "links": { - "Github": "https://github.com/JobchainOfficial", - "Homepage": "https://www.jobchain.com" - }, - "marketcap_usd": 2519134, - "name": "Jobchain", - "network": "eth", - "shortcut": "JOB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JOT": { - "address": "0xdb455c71C1bC2de4e80cA451184041Ef32054001", - "links": { - "Homepage": "https://jury.online" - }, - "marketcap_usd": 0, - "name": "Jury.Online Token", - "network": "eth", - "shortcut": "JOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JOY": { - "address": "0xDDe12a12A6f67156e0DA672be05c374e1B0a3e57", - "links": { - "Homepage": "https://joyso.io/" - }, - "marketcap_usd": 0, - "name": "JOYSO", - "network": "eth", - "shortcut": "JOY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:JSE": { - "address": "0x2d184014b5658C453443AA87c8e9C4D57285620b", - "links": { - "Github": "https://github.com/jsecoin", - "Homepage": "https://jsecoin.com" - }, - "marketcap_usd": 0, - "name": "JSE Token", - "network": "eth", - "shortcut": "JSE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KAN": { - "address": "0x1410434b0346f5bE678d0FB554E5c7ab620f8f4a", - "links": { - "Homepage": "http://www.kan.land" - }, - "marketcap_usd": 11935328, - "name": "BitKan", - "network": "eth", - "shortcut": "KAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KAPA": { - "address": "0xe15254a13D34F9700320330abcb7c7F857aF2Fb7", - "links": { - "Github": "https://github.com/kapacoin", - "Homepage": "http://kapacoin.com" - }, - "marketcap_usd": 0, - "name": "KAPA COIN", - "network": "eth", - "shortcut": "KAPA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KC": { - "address": "0x0D6DD9f68d24EC1d5fE2174f3EC8DAB52B52BaF5", - "links": { - "Homepage": "https://www.kmcc.io" - }, - "marketcap_usd": 0, - "name": "KMCC", - "network": "eth", - "shortcut": "KC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KIN": { - "address": "0x818Fc6C2Ec5986bc6E2CBf00939d90556aB12ce5", - "links": { - "Github": "https://github.com/kikinteractive/kin-token", - "Homepage": "https://kin.kik.com" - }, - "marketcap_usd": 0, - "name": "Kin Foundation", - "network": "eth", - "shortcut": "KIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KIND": { - "address": "0x4618519de4C304F3444ffa7f812dddC2971cc688", - "links": { - "Homepage": "https://kindads.io" - }, - "marketcap_usd": 0, - "name": "Kind Ads Token", - "network": "eth", - "shortcut": "KIND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KLOWN": { - "address": "0xc97A5cdF41BAfD51c8dBE82270097e704d748b92", - "links": { - "Homepage": "https://etherclown.com/" - }, - "marketcap_usd": 0, - "name": "Ether Clown", - "network": "eth", - "shortcut": "KLOWN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KNC": { - "address": "0xdd974D5C2e2928deA5F71b9825b8b646686BD200", - "links": { - "Github": "https://github.com/KyberNetwork", - "Homepage": "https://kyber.network" - }, - "marketcap_usd": 0, - "name": "Kyber Network", - "network": "eth", - "shortcut": "KNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KNDC": { - "address": "0x8E5610ab5E39d26828167640EA29823fe1dD5843", - "links": { - "Homepage": "https://kanadecoin.com" - }, - "marketcap_usd": 89020, - "name": "KanadeCoin", - "network": "eth", - "shortcut": "KNDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KNT": { - "address": "0xfF5c25D2F40B47C4a37f989DE933E26562Ef0Ac0", - "links": { - "Homepage": "https://kora.network" - }, - "marketcap_usd": 0, - "name": "Kora Network Token", - "network": "eth", - "shortcut": "KNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KPR": { - "address": "0xb5C33F965C8899D255c34CDD2A3efA8AbCbB3DeA", - "links": { - "Github": "https://github.com/KPRToken/KPR-code-for-ICO", - "Homepage": "https://www.kprms.com/" - }, - "marketcap_usd": 0, - "name": "KPRCoin", - "network": "eth", - "shortcut": "KPR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KRI": { - "address": "0xeef8102A0D46D508f171d7323BcEffc592835F13", - "links": { - "Homepage": "https://www.krios.io" - }, - "marketcap_usd": 0, - "name": "Krios", - "network": "eth", - "shortcut": "KRI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KRL": { - "address": "0x464eBE77c293E473B48cFe96dDCf88fcF7bFDAC0", - "links": { - "Github": "https://github.com/Cryptense/", - "Homepage": "https://kryll.io/" - }, - "marketcap_usd": 11584452, - "name": "Kryll", - "network": "eth", - "shortcut": "KRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KRP": { - "address": "0xAefad686f4b894ce4F9c74af755AB4651E420EbA", - "links": { - "Homepage": "https://krisper.io" - }, - "marketcap_usd": 0, - "name": "Krisper", - "network": "eth", - "shortcut": "KRP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KRTY": { - "address": "0xbD4AB8b9C26c4888e2792cAC6d5793Efea9eBb20", - "links": { - "Github": "https://github.com/kartiywallet", - "Homepage": "https://www.kartiy.com" - }, - "marketcap_usd": 0, - "name": "KARTIY", - "network": "eth", - "shortcut": "KRTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KRW-G": { - "address": "0x4CC8486F2F3dCE2d3B5E27057Cf565e16906D12D", - "links": { - "Github": "https://github.com/gluwa/Gluwacoin", - "Homepage": "https://www.gluwa.com/gluwacoin" - }, - "marketcap_usd": 0, - "name": "KRW Gluwacoin", - "network": "eth", - "shortcut": "KRW-G", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KUE": { - "address": "0xdf1338FbAfe7aF1789151627B886781ba556eF9a", - "links": { - "Homepage": "https://ico.kuende.com" - }, - "marketcap_usd": 0, - "name": "Kuende Token", - "network": "eth", - "shortcut": "KUE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KWATT": { - "address": "0x241bA672574A78a3A604CDd0a94429A73a84a324", - "links": { - "Homepage": "https://4new.io" - }, - "marketcap_usd": 0, - "name": "4NEW", - "network": "eth", - "shortcut": "KWATT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KXC": { - "address": "0x016396044709EB3edc69C44f4d5Fa6996917E4e8", - "links": { - "Homepage": "https://kingxchain.com/" - }, - "marketcap_usd": 0, - "name": "Token KingXChain", - "network": "eth", - "shortcut": "KXC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:KZN": { - "address": "0x9541FD8B9b5FA97381783783CeBF2F5fA793C262", - "links": { - "Homepage": "http://kaizencoin.io" - }, - "marketcap_usd": 0, - "name": "KaizenCoin", - "network": "eth", - "shortcut": "KZN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LA": { - "address": "0xE50365f5D679CB98a1dd62D6F6e58e59321BcdDf", - "links": { - "Github": "https://github.com/latoken", - "Homepage": "https://latoken.com/" - }, - "marketcap_usd": 12469110, - "name": "LATOKEN", - "network": "eth", - "shortcut": "LA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LALA": { - "address": "0xfD107B473AB90e8Fbd89872144a3DC92C40Fa8C9", - "links": { - "Homepage": "https://lalaworld.io/" - }, - "marketcap_usd": 0, - "name": "LALA World Token", - "network": "eth", - "shortcut": "LALA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LAMB": { - "address": "0x8971f9fd7196e5cEE2C1032B50F656855af7Dd26", - "links": { - "Github": "https://github.com/LambdaIM", - "Homepage": "https://www.lambda.im/" - }, - "marketcap_usd": 3436594, - "name": "Lambda", - "network": "eth", - "shortcut": "LAMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LATX": { - "address": "0x2f85E502a988AF76f7ee6D83b7db8d6c0A823bf9", - "links": { - "Homepage": "https://latium.org" - }, - "marketcap_usd": 0, - "name": "LatiumX", - "network": "eth", - "shortcut": "LATX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LBA": { - "address": "0xfe5F141Bf94fE84bC28deD0AB966c16B17490657", - "links": { - "Homepage": "https://www.mycred.io" - }, - "marketcap_usd": 1984754, - "name": "Cred", - "network": "eth", - "shortcut": "LBA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LCS": { - "address": "0xAA19961b6B858D9F18a115f25aa1D98ABc1fdBA8", - "links": { - "Homepage": "https://www.localcoinswap.com" - }, - "marketcap_usd": 0, - "name": "LocalCoinSwap", - "network": "eth", - "shortcut": "LCS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LDC": { - "address": "0x5102791cA02FC3595398400BFE0e33d7B6C82267", - "links": { - "Homepage": "https://www.leadcoin.network/" - }, - "marketcap_usd": 0, - "name": "LEADCOIN", - "network": "eth", - "shortcut": "LDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LDX": { - "address": "0x9eFa0e2387E4CBA02a6E4E6594b8f4Dd209a0b93", - "links": { - "Github": "https://github.com/jba123", - "Homepage": "https://londoncoin.io/" - }, - "marketcap_usd": 0, - "name": "LondonCoin", - "network": "eth", - "shortcut": "LDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LEDU": { - "address": "0x5b26C5D0772E5bbaC8b3182AE9a13f9BB2D03765", - "links": { - "Github": "https://github.com/livecodingtvofficial", - "Homepage": "https://ledu.education-ecosystem.com" - }, - "marketcap_usd": 0, - "name": "Education Ecosystem", - "network": "eth", - "shortcut": "LEDU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LEND": { - "address": "0x80fB784B7eD66730e8b1DBd9820aFD29931aab03", - "links": { - "Github": "https://github.com/ETHLend", - "Homepage": "https://aave.com/" - }, - "marketcap_usd": 0, - "name": "ETHLend", - "network": "eth", - "shortcut": "LEND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LEO": { - "address": "0xf97b5d65Da6b0468b90D531ddae2a69843e6797d", - "links": { - "Homepage": "https://www.leocoin.org/" - }, - "marketcap_usd": 0, - "name": "LEOcoin", - "network": "eth", - "shortcut": "LEO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LEV": { - "address": "0x0F4CA92660Efad97a9a70CB0fe969c755439772C", - "links": { - "Homepage": "https://www.leverj.io" - }, - "marketcap_usd": 0, - "name": "Leverj", - "network": "eth", - "shortcut": "LEV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LFR": { - "address": "0xc798cd1c49db0E297312E4c682752668CE1dB2AD", - "links": { - "Homepage": "https://www.liferun.cc" - }, - "marketcap_usd": 0, - "name": "LifeRun Coin", - "network": "eth", - "shortcut": "LFR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LGD": { - "address": "0x59061b6f26BB4A9cE5828A19d35CFD5A4B80F056", - "links": { - "Homepage": "http://legendsroomlv.com" - }, - "marketcap_usd": 0, - "name": "Legends", - "network": "eth", - "shortcut": "LGD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LGO": { - "address": "0x0a50C93c762fDD6E56D86215C24AaAD43aB629aa", - "links": { - "Github": "https://github.com/lgo-public", - "Homepage": "https://lgo.group" - }, - "marketcap_usd": 0, - "name": "LGO Token", - "network": "eth", - "shortcut": "LGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LGR": { - "address": "0x2eb86e8fC520E0F6Bb5D9Af08F924fe70558Ab89", - "links": { - "Homepage": "https://getlogarithm.com" - }, - "marketcap_usd": 0, - "name": "Logarithm", - "network": "eth", - "shortcut": "LGR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LIBER": { - "address": "0xE6DfBF1FAcA95036B8E76e1Fb28933D025B76Cc0", - "links": { - "Homepage": "https://www.libereum.io" - }, - "marketcap_usd": 0, - "name": "Libereum", - "network": "eth", - "shortcut": "LIBER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LIF": { - "address": "0xEB9951021698B42e4399f9cBb6267Aa35F82D59D", - "links": { - "Github": "https://github.com/windingtree", - "Homepage": "https://windingtree.com/" - }, - "marketcap_usd": 0, - "name": "Winding Tree", - "network": "eth", - "shortcut": "LIF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LIFE": { - "address": "0xfF18DBc487b4c2E3222d115952bABfDa8BA52F5F", - "links": { - "Homepage": "http://www.lifelabs.io" - }, - "marketcap_usd": 0, - "name": "LIFE", - "network": "eth", - "shortcut": "LIFE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LIKE": { - "address": "0x02F61Fd266DA6E8B102D4121f5CE7b992640CF98", - "links": { - "Github": "https://github.com/likecoin", - "Homepage": "https://like.co" - }, - "marketcap_usd": 0, - "name": "LikeCoin", - "network": "eth", - "shortcut": "LIKE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LINK (Chainlink)": { - "address": "0x514910771AF9Ca656af840dff83E8264EcF986CA", - "links": { - "Homepage": "https://link.smartcontract.com" - }, - "marketcap_usd": 3706867339, - "name": "Chainlink", - "network": "eth", - "shortcut": "LINK (Chainlink)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LIVE": { - "address": "0x24A77c1F17C547105E14813e517be06b0040aa76", - "links": { - "Homepage": "https://livestars.io" - }, - "marketcap_usd": 0, - "name": "LIVE Token", - "network": "eth", - "shortcut": "LIVE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LKY": { - "address": "0x49bD2DA75b1F7AF1E4dFd6b1125FEcDe59dBec58", - "links": { - "Homepage": "https://www.linkey.info" - }, - "marketcap_usd": 0, - "name": "Linkey", - "network": "eth", - "shortcut": "LKY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LML": { - "address": "0x25B6325f5BB1c1E03cfbC3e53F470E1F1ca022E3", - "links": { - "Github": "https://github.com/GNYIO", - "Homepage": "https://www.gny.io/lisk" - }, - "marketcap_usd": 513069, - "name": "Lisk Machine Learning", - "network": "eth", - "shortcut": "LML", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LMY": { - "address": "0x66fD97a78d8854fEc445cd1C80a07896B0b4851f", - "links": { - "Github": "https://github.com/LunchMoneyToken", - "Homepage": "https://www.lunchmoney.io/" - }, - "marketcap_usd": 0, - "name": "Lunch Money", - "network": "eth", - "shortcut": "LMY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LND": { - "address": "0x0947b0e6D821378805c9598291385CE7c791A6B2", - "links": { - "Github": "https://github.com/lendingblock", - "Homepage": "https://lendingblock.com" - }, - "marketcap_usd": 0, - "name": "Lendingblock", - "network": "eth", - "shortcut": "LND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOC": { - "address": "0x5e3346444010135322268a4630d2ED5F8D09446c", - "links": { - "Homepage": "https://LockChain.co" - }, - "marketcap_usd": 0, - "name": "LockChain", - "network": "eth", - "shortcut": "LOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOCI": { - "address": "0x9c23D67AEA7B95D80942e3836BCDF7E708A747C2", - "links": { - "Github": "http://github.com/locipro/loci-coin-sale", - "Homepage": "https://locipro.com" - }, - "marketcap_usd": 0, - "name": "LOCIcoin", - "network": "eth", - "shortcut": "LOCI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOCUS": { - "address": "0xC64500DD7B0f1794807e67802F8Abbf5F8Ffb054", - "links": { - "Homepage": "https://www.locuschain.com" - }, - "marketcap_usd": 106084983, - "name": "Locus Chain", - "network": "eth", - "shortcut": "LOCUS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOK": { - "address": "0x21aE23B882A340A22282162086bC98D3E2B73018", - "links": { - "Homepage": "https://lookrev.com" - }, - "marketcap_usd": 0, - "name": "LOK", - "network": "eth", - "shortcut": "LOK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOOK": { - "address": "0x253C7dd074f4BaCb305387F922225A4f737C08bd", - "links": { - "Homepage": "https://lookrev.com" - }, - "marketcap_usd": 0, - "name": "LookRev", - "network": "eth", - "shortcut": "LOOK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOOKS": { - "address": "0xf4d2888d29D722226FafA5d9B24F9164c092421E", - "links": { - "Homepage": "https://looksrare.org/" - }, - "marketcap_usd": 87358911, - "name": "LooksRare", - "network": "eth", - "shortcut": "LOOKS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LOOM": { - "address": "0x42476F744292107e34519F9c357927074Ea3F75D", - "links": { - "Github": "github.com/loomnetwork/", - "Homepage": "https://loomx.io" - }, - "marketcap_usd": 68665519, - "name": "LOOM", - "network": "eth", - "shortcut": "LOOM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LPT": { - "address": "0x58b6A8A3302369DAEc383334672404Ee733aB239", - "links": { - "Github": "https://github.com/livepeer", - "Homepage": "https://livepeer.org/" - }, - "marketcap_usd": 202398732, - "name": "Livepeer Token", - "network": "eth", - "shortcut": "LPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LQD": { - "address": "0xD29F0b5b3F50b07Fe9a9511F7d86F4f4bAc3f8c4", - "links": { - "Homepage": "https://liquidity.network/" - }, - "marketcap_usd": 0, - "name": "Liquidity Network Token", - "network": "eth", - "shortcut": "LQD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LRC": { - "address": "0xBBbbCA6A901c926F240b89EacB641d8Aec7AEafD", - "links": { - "Github": "https://github.com/loopring", - "Homepage": "https://loopring.org" - }, - "marketcap_usd": 488986992, - "name": "Loopring", - "network": "eth", - "shortcut": "LRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LUC": { - "address": "0x5dbe296F97B23C4A6AA6183D73e574D02bA5c719", - "links": { - "Github": "https://github.com/Play2Live/blockchain", - "Homepage": "https://play2live.io" - }, - "marketcap_usd": 0, - "name": "LUCToken", - "network": "eth", - "shortcut": "LUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LUCHOW": { - "address": "0xA5Ef74068d04ba0809B7379dD76Af5Ce34Ab7C57", - "links": { - "Github": "https://github.com/lunachoww/contract", - "Homepage": "https://lunachow.com" - }, - "marketcap_usd": 0, - "name": "LunaChow", - "network": "eth", - "shortcut": "LUCHOW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LUCK": { - "address": "0xFB12e3CcA983B9f59D90912Fd17F8D745A8B2953", - "links": { - "Homepage": "http://www.luckytoken.info" - }, - "marketcap_usd": 0, - "name": "LUCK", - "network": "eth", - "shortcut": "LUCK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LUM": { - "address": "0xA89b5934863447f6E4Fc53B315a93e873bdA69a3", - "links": { - "Homepage": "https://www.luminocoin.com" - }, - "marketcap_usd": 0, - "name": "Lumino Coin", - "network": "eth", - "shortcut": "LUM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LUN": { - "address": "0xfa05A73FfE78ef8f1a739473e462c54bae6567D9", - "links": { - "Github": "https://github.com/lunyr", - "Homepage": "https://lunyr.com" - }, - "marketcap_usd": 39214, - "name": "Lunyr", - "network": "eth", - "shortcut": "LUN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LVN": { - "address": "0xc8Cac7672f4669685817cF332a33Eb249F085475", - "links": { - "Github": "https://github.com/livenpay", - "Homepage": "https://livenpay.io" - }, - "marketcap_usd": 0, - "name": "LivenCoin", - "network": "eth", - "shortcut": "LVN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:LYS": { - "address": "0xdD41fBd1Ae95C5D9B198174A28e04Be6b3d1aa27", - "links": { - "Github": "https://github.com/LIGHTYEARS-LYS/LIGHTYEARS-Token", - "Homepage": "https://lightyearstoken.com" - }, - "marketcap_usd": 0, - "name": "Lightyears", - "network": "eth", - "shortcut": "LYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:M-ETH": { - "address": "0x3f4B726668da46f5e0E75aA5D478ACEc9f38210F", - "links": { - "Homepage": "http://www.mostexclusive.com" - }, - "marketcap_usd": 0, - "name": "M-ETH", - "network": "eth", - "shortcut": "M-ETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MAD": { - "address": "0x5B09A0371C1DA44A8E24D36Bf5DEb1141a84d875", - "links": { - "Homepage": "https://madnetwork.io" - }, - "marketcap_usd": 0, - "name": "MAD", - "network": "eth", - "shortcut": "MAD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MAGIC": { - "address": "0xB0c7a3Ba49C7a6EaBa6cD4a96C55a1391070Ac9A", - "links": { - "Github": "https://github.com/TreasureProject", - "Homepage": "https://treasure.lol/" - }, - "marketcap_usd": 334874623, - "name": "MAGIC", - "network": "eth", - "shortcut": "MAGIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MAN": { - "address": "0xe25bCec5D3801cE3a794079BF94adF1B8cCD802D", - "links": { - "Github": "https://github.com/MatrixAINetwork", - "Homepage": "https://www.matrix.io" - }, - "marketcap_usd": 0, - "name": "Matrix AI Network", - "network": "eth", - "shortcut": "MAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MANA": { - "address": "0x0F5D2fB29fb7d3CFeE444a200298f468908cC942", - "links": { - "Github": "https://github.com/decentraland", - "Homepage": "https://decentraland.org" - }, - "marketcap_usd": 1197020889, - "name": "Decentraland MANA", - "network": "eth", - "shortcut": "MANA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MART": { - "address": "0xfdcc07Ab60660de533b5Ad26e1457b565a9D59Bd", - "links": { - "Homepage": "https://martcoin.io" - }, - "marketcap_usd": 0, - "name": "Martcoin", - "network": "eth", - "shortcut": "MART", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MAS": { - "address": "0x23Ccc43365D9dD3882eab88F43d515208f832430", - "links": { - "Homepage": "https://midasprotocol.io/" - }, - "marketcap_usd": 46340, - "name": "MIDAS PROTOCOL", - "network": "eth", - "shortcut": "MAS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MATIC": { - "address": "0x7D1AfA7B718fb893dB30A3aBc0Cfc608AaCfeBB0", - "links": { - "Homepage": "https://polygon.technology/" - }, - "marketcap_usd": 10673372779, - "name": "Matic Token", - "network": "eth", - "shortcut": "MATIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MBRS": { - "address": "0x386467F1f3ddbE832448650418311a479EECFC57", - "links": { - "Github": "https://github.com/theembermine", - "Homepage": "https://embermine.com/" - }, - "marketcap_usd": 0, - "name": "Embers", - "network": "eth", - "shortcut": "MBRS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MCAP": { - "address": "0x93E682107d1E9defB0b5ee701C71707a4B2E46Bc", - "links": { - "Homepage": "https://bitcoingrowthfund.com/mcap" - }, - "marketcap_usd": 0, - "name": "MCAP", - "network": "eth", - "shortcut": "MCAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MCI": { - "address": "0x138A8752093F4f9a79AaeDF48d4B9248fab93c9C", - "links": { - "Github": "https://github.com/musiconomi/", - "Homepage": "https://musiconomi.com/" - }, - "marketcap_usd": 0, - "name": "Musiconomi", - "network": "eth", - "shortcut": "MCI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MCO": { - "address": "0xB63B606Ac810a52cCa15e44bB630fd42D8d1d83d", - "links": { - "Homepage": "https://crypto.com" - }, - "marketcap_usd": 0, - "name": "Crypto.com", - "network": "eth", - "shortcut": "MCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MDA": { - "address": "0x51DB5Ad35C671a87207d88fC11d593AC0C8415bd", - "links": { - "Homepage": "https://moedaseeds.com" - }, - "marketcap_usd": 1291844, - "name": "Moeda Loyalty Points", - "network": "eth", - "shortcut": "MDA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MDT": { - "address": "0x814e0908b12A99FeCf5BC101bB5d0b8B5cDf7d26", - "links": { - "Homepage": "https://www.mdt.co" - }, - "marketcap_usd": 41400337, - "name": "Measurable Data Token", - "network": "eth", - "shortcut": "MDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MDX": { - "address": "0x947AEb02304391f8fbE5B25D7D98D649b57b1788", - "links": { - "Homepage": "https://trade.mandala.exchange" - }, - "marketcap_usd": 0, - "name": "Mandala Exchange Token", - "network": "eth", - "shortcut": "MDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MEDCASH": { - "address": "0x6652Fa201B6BBBC0b5b0aD3f5702b2B9849cc830", - "links": { - "Homepage": "https://medxchange.io" - }, - "marketcap_usd": 0, - "name": "MEDCASH", - "network": "eth", - "shortcut": "MEDCASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MEDX": { - "address": "0xfd1e80508F243E64CE234eA88A5Fd2827c71D4b7", - "links": { - "Homepage": "https://medibloc.org" - }, - "marketcap_usd": 0, - "name": "MediBloc [ERC20]", - "network": "eth", - "shortcut": "MEDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MEME": { - "address": "0xD5525D397898e5502075Ea5E830d8914f6F0affe", - "links": { - "Homepage": "https://dontbuymeme.com" - }, - "marketcap_usd": 1541109, - "name": "Meme", - "network": "eth", - "shortcut": "MEME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MESG": { - "address": "0x420167D87d35c3A249b32Ef6225872fBD9aB85D2", - "links": { - "Github": "https://github.com/mesg-foundation", - "Homepage": "https://mesg.com" - }, - "marketcap_usd": 0, - "name": "MESG", - "network": "eth", - "shortcut": "MESG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MEST": { - "address": "0x5B8D43FfdE4a2982B9A5387cDF21D54Ead64Ac8d", - "links": { - "Github": "https://github.com/monacoestate", - "Homepage": "https://monacoestate.io/" - }, - "marketcap_usd": 0, - "name": "Monaco Estate", - "network": "eth", - "shortcut": "MEST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:METM": { - "address": "0xFEF3884b603C33EF8eD4183346E093A173C94da6", - "links": { - "Homepage": "https://metamorph.pro" - }, - "marketcap_usd": 0, - "name": "MetaMorph", - "network": "eth", - "shortcut": "METM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MFG": { - "address": "0x6710c63432A2De02954fc0f851db07146a6c0312", - "links": { - "Github": "https://github.com/syncfab", - "Homepage": "https://syncfab.com/" - }, - "marketcap_usd": 1569704, - "name": "SyncFab Smart Manufacturing Blockchain", - "network": "eth", - "shortcut": "MFG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MFT": { - "address": "0xDF2C7238198Ad8B389666574f2d8bc411A4b7428", - "links": { - "Github": "https://github.com/MainframeHQ", - "Homepage": "https://mainframe.com" - }, - "marketcap_usd": 46148389, - "name": "Mainframe Token", - "network": "eth", - "shortcut": "MFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MFTU": { - "address": "0x05D412CE18F24040bB3Fa45CF2C69e506586D8e8", - "links": { - "Homepage": "https://mftu.net" - }, - "marketcap_usd": 0, - "name": "Mainstream For The Underground", - "network": "eth", - "shortcut": "MFTU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MGO": { - "address": "0x40395044Ac3c0C57051906dA938B54BD6557F212", - "links": { - "Homepage": "https://mobilego.io" - }, - "marketcap_usd": 0, - "name": "MobileGo", - "network": "eth", - "shortcut": "MGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MHLK": { - "address": "0xE3D0a162fCc5c02C9448274D7C58E18e1811385f", - "links": { - "Github": "https://github.com/maharlikacoin", - "Homepage": "https://www.maharlikacoin.com" - }, - "marketcap_usd": 0, - "name": "Maharlika Coin", - "network": "eth", - "shortcut": "MHLK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MIC": { - "address": "0x3A1237D38D0Fb94513f85D61679cAd7F38507242", - "links": { - "Homepage": "https://mindexcoin.com" - }, - "marketcap_usd": 0, - "name": "Mindexcoin", - "network": "eth", - "shortcut": "MIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MILC": { - "address": "0xD717B75404022fb1C8582ADf1c66B9A553811754", - "links": { - "Homepage": "https://www.milc.global" - }, - "marketcap_usd": 0, - "name": "Micro Licensing Coin", - "network": "eth", - "shortcut": "MILC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MINDS": { - "address": "0xB26631c6dda06aD89B93C71400D25692de89c068", - "links": { - "Homepage": "https://www.minds.com/" - }, - "marketcap_usd": 0, - "name": "Minds Token", - "network": "eth", - "shortcut": "MINDS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MITX": { - "address": "0x4a527d8fc13C5203AB24BA0944F4Cb14658D1Db6", - "links": { - "Homepage": "https://token.morpheuslabs.io" - }, - "marketcap_usd": 9699325, - "name": "Morpheus Infrastructure Token", - "network": "eth", - "shortcut": "MITX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MKR": { - "address": "0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2", - "links": { - "Github": "https://github.com/makerdao", - "Homepage": "https://makerdao.com" - }, - "marketcap_usd": 754815596, - "name": "MakerDAO", - "network": "eth", - "shortcut": "MKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MKT": { - "address": "0x7939882b54fcf0bCAe6b53dEc39Ad6e806176442", - "links": { - "Github": "https://github.com/mikadohq", - "Homepage": "https://mikado.io" - }, - "marketcap_usd": 0, - "name": "Mikado", - "network": "eth", - "shortcut": "MKT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MLN (new)": { - "address": "0xec67005c4E498Ec7f55E092bd1d35cbC47C91892", - "links": { - "Homepage": "https://melonport.com" - }, - "marketcap_usd": 51522892, - "name": "Melonport", - "network": "eth", - "shortcut": "MLN (new)", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MM": { - "address": "0x6B4c7A5e3f0B99FCD83e9c089BDDD6c7FCe5c611", - "links": { - "Homepage": "https://www.milliontoken.org" - }, - "marketcap_usd": 0, - "name": "Million", - "network": "eth", - "shortcut": "MM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MNE": { - "address": "0x1a95B271B0535D15fa49932Daba31BA612b52946", - "links": { - "Homepage": "https://minereum.com" - }, - "marketcap_usd": 0, - "name": "Minereum", - "network": "eth", - "shortcut": "MNE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MNL": { - "address": "0x0d62dc6Cd8C81dCA8cAADcCF01FfE7C1F31D9402", - "links": { - "Homepage": "https://www.moonlite.io/" - }, - "marketcap_usd": 0, - "name": "Moonlite", - "network": "eth", - "shortcut": "MNL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MNT": { - "address": "0xA9877b1e05D035899131DBd1e403825166D09f92", - "links": { - "Github": "https://github.com/coinjoker/cjtoken", - "Homepage": "https://coinjoker.com" - }, - "marketcap_usd": 0, - "name": "Media Network Token", - "network": "eth", - "shortcut": "MNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MNTP": { - "address": "0x83cee9e086A77e492eE0bB93C2B0437aD6fdECCc", - "links": { - "Github": "https://github.com/Goldmint", - "Homepage": "https://goldmint.io" - }, - "marketcap_usd": 187104, - "name": "Goldmint MNT Prelaunch Token", - "network": "eth", - "shortcut": "MNTP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MOD": { - "address": "0x957c30aB0426e0C93CD8241E2c60392d08c6aC8e", - "links": { - "Github": "https://github.com/modum-io", - "Homepage": "https://modum.io" - }, - "marketcap_usd": 0, - "name": "Modum", - "network": "eth", - "shortcut": "MOD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MORE": { - "address": "0x501262281B2Ba043e2fbf14904980689CDDB0C78", - "links": { - "Homepage": "http://www.mithrilore.io" - }, - "marketcap_usd": 0, - "name": "Mithril Ore", - "network": "eth", - "shortcut": "MORE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MOT": { - "address": "0x263c618480DBe35C300D8d5EcDA19bbB986AcaeD", - "links": { - "Homepage": "https://olympuslabs.io" - }, - "marketcap_usd": 0, - "name": "Olympus Labs", - "network": "eth", - "shortcut": "MOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MRK": { - "address": "0xf453B5B9d4E0B5c62ffB256BB2378cc2BC8e8a89", - "links": { - "Homepage": "https://mark.space" - }, - "marketcap_usd": 0, - "name": "MARK.SPACE", - "network": "eth", - "shortcut": "MRK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MRL": { - "address": "0x82125AFe01819Dff1535D0D6276d57045291B6c0", - "links": { - "Github": "https://github.com/MarceloMRL", - "Homepage": "https://moneyrebel.io/" - }, - "marketcap_usd": 0, - "name": "Marcelo", - "network": "eth", - "shortcut": "MRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MRP": { - "address": "0x21f0F0fD3141Ee9E11B3d7f13a1028CD515f459c", - "links": { - "Homepage": "https://moneyrebel.io/" - }, - "marketcap_usd": 0, - "name": "MoneyRebel Token", - "network": "eth", - "shortcut": "MRP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MRS": { - "address": "0x9Af5A20AaC8D83230ba68542Ba29d132d50cbe08", - "links": { - "Homepage": "https://marsanexchange.com/" - }, - "marketcap_usd": 0, - "name": "Marsan Exchange Token", - "network": "eth", - "shortcut": "MRS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MRV": { - "address": "0xAB6CF87a50F17d7F5E1FEaf81B6fE9FfBe8EBF84", - "links": { - "Homepage": "https://macroverse.io" - }, - "marketcap_usd": 0, - "name": "MRV", - "network": "eth", - "shortcut": "MRV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MSP": { - "address": "0x68AA3F232dA9bdC2343465545794ef3eEa5209BD", - "links": { - "Homepage": "https://mothership.cx" - }, - "marketcap_usd": 0, - "name": "Mothership", - "network": "eth", - "shortcut": "MSP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTA": { - "address": "0xa3BeD4E1c75D00fa6f4E5E6922DB7261B5E9AcD2", - "links": { - "Github": "https://github.com/mstable", - "Homepage": "http://mstable.org" - }, - "marketcap_usd": 1711726, - "name": "mStable Meta", - "network": "eth", - "shortcut": "MTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTH": { - "address": "0xaF4DcE16Da2877f8c9e00544c93B62Ac40631F16", - "links": { - "Homepage": "http://www.monetha.io" - }, - "marketcap_usd": 3108167, - "name": "Monetha", - "network": "eth", - "shortcut": "MTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTL": { - "address": "0xF433089366899D83a9f26A773D59ec7eCF30355e", - "links": { - "Homepage": "https://www.metalpay.com" - }, - "marketcap_usd": 86278153, - "name": "Metal", - "network": "eth", - "shortcut": "MTL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTN": { - "address": "0x41dBECc1cdC5517C6f76f6a6E836aDbEe2754DE3", - "links": { - "Homepage": "https://medicalchain.com" - }, - "marketcap_usd": 569197, - "name": "MedToken", - "network": "eth", - "shortcut": "MTN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTR": { - "address": "0x7FC408011165760eE31bE2BF20dAf450356692Af", - "links": { - "Homepage": "https://mitrav.co" - }, - "marketcap_usd": 0, - "name": "Mitrav", - "network": "eth", - "shortcut": "MTR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTRc": { - "address": "0x1e49fF77c355A3e38D6651ce8404AF0E48c5395f", - "links": { - "Homepage": "https://modultrade.io" - }, - "marketcap_usd": 0, - "name": "MTRCToken", - "network": "eth", - "shortcut": "MTRc", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MTX": { - "address": "0x0AF44e2784637218dD1D32A322D44e603A8f0c6A", - "links": { - "Homepage": "https://www.matryx.ai" - }, - "marketcap_usd": 0, - "name": "Matryx", - "network": "eth", - "shortcut": "MTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MUSH": { - "address": "0xea6412Fb370e8d1605E6aEeAA21aD07C3C7e9F24", - "links": { - "Github": "https://github.com/anthonykarter100/MUSHToken", - "Homepage": "https://www.mushroom.community/" - }, - "marketcap_usd": 0, - "name": "Mushroom", - "network": "eth", - "shortcut": "MUSH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MUXE": { - "address": "0x515669d308f887Fd83a471C7764F5d084886D34D", - "links": { - "Homepage": "https://www.muxe.io" - }, - "marketcap_usd": 0, - "name": "MUXE", - "network": "eth", - "shortcut": "MUXE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MVG": { - "address": "0x71396a6410249725C5609646c4e449C6c4d41E27", - "links": { - "Homepage": "https://mvgtoken.io" - }, - "marketcap_usd": 0, - "name": "Max", - "network": "eth", - "shortcut": "MVG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MVL": { - "address": "0xA849EaaE994fb86Afa73382e9Bd88c2B6b18Dc71", - "links": { - "Homepage": "http://mvlchain.io" - }, - "marketcap_usd": 103186956, - "name": "Mass Vehicle Ledger Token", - "network": "eth", - "shortcut": "MVL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MVP": { - "address": "0x8a77e40936BbC27e80E9a3F526368C967869c86D", - "links": { - "Github": "https://github.com/Merculet", - "Homepage": "https://www.merculet.io" - }, - "marketcap_usd": 364084, - "name": "Merculet", - "network": "eth", - "shortcut": "MVP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MWAT": { - "address": "0x6425c6BE902d692AE2db752B3c268AFAdb099D3b", - "links": { - "Homepage": "https://www.restartenergy.io" - }, - "marketcap_usd": 0, - "name": "RED MWAT", - "network": "eth", - "shortcut": "MWAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:MYST": { - "address": "0x4Cf89ca06ad997bC732Dc876ed2A7F26a9E7f361", - "links": { - "Homepage": "https://mysterium.network/" - }, - "marketcap_usd": 5220095, - "name": "Mysterium", - "network": "eth", - "shortcut": "MYST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NAC": { - "address": "0x8d80de8A78198396329dfA769aD54d24bF90E7aa", - "links": { - "Homepage": "https://nami.trade" - }, - "marketcap_usd": 0, - "name": "Nami ICO", - "network": "eth", - "shortcut": "NAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NANJ": { - "address": "0xFFE02ee4C69eDf1b340fCaD64fbd6b37a7b9e265", - "links": { - "Github": "https://github.com/NANJ-COIN", - "Homepage": "https://nanjcoin.com/" - }, - "marketcap_usd": 315039, - "name": "NANJCOIN", - "network": "eth", - "shortcut": "NANJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NAOS": { - "address": "0x4a615bB7166210CCe20E6642a6f8Fb5d4D044496", - "links": { - "Homepage": "https://naos.finance/" - }, - "marketcap_usd": 0, - "name": "NAOS Finance", - "network": "eth", - "shortcut": "NAOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NAS": { - "address": "0x5d65D971895Edc438f465c17DB6992698a52318D", - "links": { - "Homepage": "https://nebulas.io/index.html" - }, - "marketcap_usd": 0, - "name": "Nebula", - "network": "eth", - "shortcut": "NAS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NAVI": { - "address": "0x588047365dF5BA589F923604AAC23d673555c623", - "links": { - "Github": "https://github.com/naviworld", - "Homepage": "https://naviaddress.com" - }, - "marketcap_usd": 0, - "name": "NaviToken", - "network": "eth", - "shortcut": "NAVI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NBAI": { - "address": "0x17f8aFB63DfcDcC90ebE6e84F060Cc306A98257D", - "links": { - "Github": "https://github.com/nebulaai", - "Homepage": "https://tokensale.nebula-ai.network" - }, - "marketcap_usd": 0, - "name": "NebulaAiToken", - "network": "eth", - "shortcut": "NBAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NBC": { - "address": "0x9F195617fA8fbAD9540C5D113A99A0a0172aaEDC", - "links": { - "Homepage": "https://niobiumcoin.io" - }, - "marketcap_usd": 89666, - "name": "Niobium Coin", - "network": "eth", - "shortcut": "NBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NCASH": { - "address": "0x809826cceAb68c387726af962713b64Cb5Cb3CCA", - "links": { - "Homepage": "https://nucleus.vision" - }, - "marketcap_usd": 0, - "name": "Nucleus Vision", - "network": "eth", - "shortcut": "NCASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NCR": { - "address": "0xDB5C3C46E28B53a39C255AA39A411dD64e5fed9c", - "links": { - "Github": "https://github.com/Frooxius/NeosPublic", - "Homepage": "https://neos.com/" - }, - "marketcap_usd": 0, - "name": "Neos Credits", - "network": "eth", - "shortcut": "NCR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NCT": { - "address": "0x9E46A38F5DaaBe8683E10793b06749EEF7D733d1", - "links": { - "Github": "https://github.com/polyswarm", - "Homepage": "https://polyswarm.io" - }, - "marketcap_usd": 16924718, - "name": "Nectar", - "network": "eth", - "shortcut": "NCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NDC": { - "address": "0xA54ddC7B3CcE7FC8b1E3Fa0256D0DB80D2c10970", - "links": { - "Homepage": "https://neverdie.com" - }, - "marketcap_usd": 0, - "name": "Neverdie", - "network": "eth", - "shortcut": "NDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NDX": { - "address": "0x1966d718A565566e8E202792658D7b5Ff4ECe469", - "links": { - "Github": "https://github.com/ndexnetwork/NDX", - "Homepage": "https://ndexnetwork.com" - }, - "marketcap_usd": 0, - "name": "nDEX", - "network": "eth", - "shortcut": "NDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NEC": { - "address": "0xCc80C051057B774cD75067Dc48f8987C4Eb97A5e", - "links": { - "Github": "https://github.com/ethfinex/", - "Homepage": "https://nectar.community" - }, - "marketcap_usd": 0, - "name": "Ethfinex Nectar Token", - "network": "eth", - "shortcut": "NEC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NEEO": { - "address": "0xd8446236FA95b9b5f9fd0f8E7Df1a944823c683d", - "links": { - "Homepage": "http://neeoico.com/" - }, - "marketcap_usd": 0, - "name": "NEEO", - "network": "eth", - "shortcut": "NEEO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NET": { - "address": "0xcfb98637bcae43C13323EAa1731cED2B716962fD", - "links": { - "Homepage": "https://nimiq.com" - }, - "marketcap_usd": 0, - "name": "NIMIQ", - "network": "eth", - "shortcut": "NET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NEU": { - "address": "0xA823E6722006afe99E91c30FF5295052fe6b8E32", - "links": { - "Github": "https://github.com/neufund", - "Homepage": "https://neufund.org" - }, - "marketcap_usd": 0, - "name": "NEU Fund", - "network": "eth", - "shortcut": "NEU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NEXO": { - "address": "0xB62132e35a6c13ee1EE0f84dC5d40bad8d815206", - "links": { - "Homepage": "http://nexo.io" - }, - "marketcap_usd": 392895017, - "name": "Nexo", - "network": "eth", - "shortcut": "NEXO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NFTL": { - "address": "0x3c8D2FCE49906e11e71cB16Fa0fFeB2B16C29638", - "links": { - "Homepage": "https://niftyleague.com/" - }, - "marketcap_usd": 0, - "name": "Nifty League", - "network": "eth", - "shortcut": "NFTL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NGC": { - "address": "0x72dD4b6bd852A3AA172Be4d6C5a6dbEc588cf131", - "links": { - "Homepage": "https://www.nagaico.com" - }, - "marketcap_usd": 0, - "name": "NAGA Coin", - "network": "eth", - "shortcut": "NGC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NIMFA": { - "address": "0xe26517A9967299453d3F1B48Aa005E6127e67210", - "links": { - "Github": "https://github.com/nimfamoney", - "Homepage": "https://nimfamoney.io" - }, - "marketcap_usd": 0, - "name": "Ninfa Money", - "network": "eth", - "shortcut": "NIMFA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NKN": { - "address": "0x5Cf04716BA20127F1E2297AdDCf4B5035000c9eb", - "links": { - "Github": "https://github.com/nknorg", - "Homepage": "https://nkn.org" - }, - "marketcap_usd": 90576077, - "name": "NKN", - "network": "eth", - "shortcut": "NKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NLYA": { - "address": "0xCeE4019Fd41ECDc8bae9EFDd20510f4b6FAA6197", - "links": { - "Github": "https://github.com/nollyacoin/", - "Homepage": "https://nollya.com" - }, - "marketcap_usd": 0, - "name": "Nollya Coin", - "network": "eth", - "shortcut": "NLYA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NMR": { - "address": "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671", - "links": { - "Github": "https://github.com/numerai", - "Homepage": "https://numer.ai" - }, - "marketcap_usd": 116826641, - "name": "Numerai", - "network": "eth", - "shortcut": "NMR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NOAH": { - "address": "0x58a4884182d9E835597f405e5F258290E46ae7C2", - "links": { - "Github": "https://github.com/NoahFoundation/NoahCoin", - "Homepage": "https://noahcoin.org" - }, - "marketcap_usd": 0, - "name": "Noah Coin", - "network": "eth", - "shortcut": "NOAH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NOBS": { - "address": "0xF4FaEa455575354d2699BC209B0a65CA99F69982", - "links": { - "Homepage": "https://nobscrypto.com" - }, - "marketcap_usd": 0, - "name": "No BS Crypto", - "network": "eth", - "shortcut": "NOBS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NOX": { - "address": "0xeC46f8207D766012454c408De210BCBc2243E71c", - "links": { - "Github": "https://github.com/nitrotoken/nitro-crowdsale", - "Homepage": "https://nitro.live" - }, - "marketcap_usd": 0, - "name": "Nitro", - "network": "eth", - "shortcut": "NOX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NPER": { - "address": "0x4cE6B362Bc77A24966Dda9078f9cEF81b3B886a7", - "links": { - "Github": "https://github.com/NperProject", - "Homepage": "https://nper.io" - }, - "marketcap_usd": 0, - "name": "NPER", - "network": "eth", - "shortcut": "NPER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NPX": { - "address": "0x28b5E12CcE51f15594B0b91d5b5AdaA70F684a02", - "links": { - "Homepage": "https://napoleonx.ai" - }, - "marketcap_usd": 0, - "name": "NaPoleonX", - "network": "eth", - "shortcut": "NPX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NPXS": { - "address": "0xA15C7Ebe1f07CaF6bFF097D8a589fb8AC49Ae5B3", - "links": { - "Github": "https://github.com/pundix", - "Homepage": "https://pundix.com" - }, - "marketcap_usd": 133949059, - "name": "Pundi X Token", - "network": "eth", - "shortcut": "NPXS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NRM": { - "address": "0x000000085824F23a070c2474442ED014c0e46B58", - "links": { - "Github": "https://github.com/NRM-Neuromachine", - "Homepage": "https://nrm.world" - }, - "marketcap_usd": 0, - "name": "Neuromachine Eternal", - "network": "eth", - "shortcut": "NRM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NTO": { - "address": "0x8A99ED8a1b204903Ee46e733f2c1286F6d20b177", - "links": { - "Homepage": "https://fujinto.io" - }, - "marketcap_usd": 0, - "name": "Fujinto", - "network": "eth", - "shortcut": "NTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NU": { - "address": "0x4fE83213D56308330EC302a8BD641f1d0113A4Cc", - "links": { - "Github": "https://github.com/nucypher", - "Homepage": "https://nucypher.com" - }, - "marketcap_usd": 106813292, - "name": "NuCypher Network", - "network": "eth", - "shortcut": "NU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NUG": { - "address": "0x245ef47D4d0505ECF3Ac463F4d81f41ADE8f1fd1", - "links": { - "Homepage": "https://nuggets.life/" - }, - "marketcap_usd": 0, - "name": "Nuggets Token", - "network": "eth", - "shortcut": "NUG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NUKE": { - "address": "0xc58c0Fca06908E66540102356f2E91edCaEB8D81", - "links": { - "Github": "https://github.com/halflifecode", - "Homepage": "https://nuketoken.com" - }, - "marketcap_usd": 0, - "name": "HalfLife", - "network": "eth", - "shortcut": "NUKE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NULS": { - "address": "0xB91318F35Bdb262E9423Bc7c7c2A3A93DD93C92C", - "links": { - "Homepage": "https://nuls.io" - }, - "marketcap_usd": 0, - "name": "NULS", - "network": "eth", - "shortcut": "NULS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NUMA": { - "address": "0x303D396bB1E2A73b1536665964aa9f5AA0f7f9cA", - "links": { - "Homepage": "http://www.numismacoins.com/" - }, - "marketcap_usd": 0, - "name": "Numisma Coin", - "network": "eth", - "shortcut": "NUMA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NUSD": { - "address": "0x0C6144c16af288948C8fdB37fD8fEc94bfF3d1d9", - "links": { - "Github": "https://github.com/NeutralGroup", - "Homepage": "https://neutralproject.com" - }, - "marketcap_usd": 0, - "name": "Neutral Dollar", - "network": "eth", - "shortcut": "NUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NXX": { - "address": "0x7627de4B93263a6a7570b8dAfa64bae812e5c394", - "links": { - "Homepage": "https://www.nexxuscoin.com" - }, - "marketcap_usd": 0, - "name": "NXX", - "network": "eth", - "shortcut": "NXX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:NxC": { - "address": "0x45e42D659D9f9466cD5DF622506033145a9b89Bc", - "links": { - "Homepage": "https://beyond-the-void.net" - }, - "marketcap_usd": 0, - "name": "Nexium", - "network": "eth", - "shortcut": "NxC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OAK": { - "address": "0x5e888B83B7287EED4fB7DA7b7d0A0D4c735d94b3", - "links": { - "Homepage": "https://aco.ai" - }, - "marketcap_usd": 0, - "name": "OAK", - "network": "eth", - "shortcut": "OAK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OAX": { - "address": "0x701C244b988a513c945973dEFA05de933b23Fe1D", - "links": { - "Homepage": "https://www.openanx.org/en" - }, - "marketcap_usd": 18826379, - "name": "OAX", - "network": "eth", - "shortcut": "OAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OBC": { - "address": "0x43E577338d6C07bc92a06C8CA4B781470515dFA8", - "links": { - "Github": "https://github.com/Oblichain-team/Oblichain", - "Homepage": "https://oblichain.com/en/home" - }, - "marketcap_usd": 0, - "name": "Oblichain", - "network": "eth", - "shortcut": "OBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OCC": { - "address": "0x0235fE624e044A05eeD7A43E16E3083bc8A4287A", - "links": { - "Github": "https://github.com/OriginalCrypto/", - "Homepage": "https://www.OriginalCryptoCoin.com/" - }, - "marketcap_usd": 0, - "name": "Original Crypto Coin", - "network": "eth", - "shortcut": "OCC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OCEAN": { - "address": "0x967da4048cD07aB37855c090aAF366e4ce1b9F48", - "links": { - "Github": "https://github.com/oceanprotocol", - "Homepage": "https://oceanprotocol.com" - }, - "marketcap_usd": 241205777, - "name": "Ocean Token", - "network": "eth", - "shortcut": "OCEAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OCN": { - "address": "0x4092678e4E78230F46A1534C0fbc8fA39780892B", - "links": { - "Homepage": "http://www.ocnex.net" - }, - "marketcap_usd": 453298, - "name": "Odyssey", - "network": "eth", - "shortcut": "OCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OCTO": { - "address": "0x7240aC91f01233BaAf8b064248E80feaA5912BA3", - "links": { - "Github": "https://github.com/octofi", - "Homepage": "https://octo.fi" - }, - "marketcap_usd": 1060203, - "name": "OctoFi", - "network": "eth", - "shortcut": "OCTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ODE": { - "address": "0xbf52F2ab39e26E0951d2a02b49B7702aBe30406a", - "links": { - "Github": "https://github.com/odemio", - "Homepage": "https://odem.io/" - }, - "marketcap_usd": 0, - "name": "ODEM Token", - "network": "eth", - "shortcut": "ODE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OGK": { - "address": "0x5f4506dB5b568e103532F84d32A285cDd5Aa5751", - "links": { - "Github": "https://github.com/organikcoin", - "Homepage": "https://organik.net.br/" - }, - "marketcap_usd": 0, - "name": "Organik", - "network": "eth", - "shortcut": "OGK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OGN": { - "address": "0x8207c1FfC5B6804F6024322CcF34F29c3541Ae26", - "links": { - "Github": "https://github.com/originprotocol", - "Homepage": "https://www.originprotocol.com" - }, - "marketcap_usd": 69749547, - "name": "OriginToken", - "network": "eth", - "shortcut": "OGN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OGV": { - "address": "0x9c354503C38481a7A7a51629142963F98eCC12D0", - "links": { - "Github": "https://github.com/OriginProtocol/ousd-governance", - "Homepage": "https://governance.ousd.com" - }, - "marketcap_usd": 4568560, - "name": "Origin Dollar Governance", - "network": "eth", - "shortcut": "OGV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OIKOS": { - "address": "0x21E13cB3F3F26f92A62ac7Adab4093e8997D1fb1", - "links": { - "Github": "https://github.com/SibuToken/oikos", - "Homepage": "http://neoarchitects.io" - }, - "marketcap_usd": 0, - "name": "OIKOS", - "network": "eth", - "shortcut": "OIKOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OJX": { - "address": "0xBeef546ac8a4e0a80DC1E2d696968Ef54138f1d4", - "links": { - "Github": "https://github.com/OjoooInc", - "Homepage": "https://ico.ojooo.com/" - }, - "marketcap_usd": 0, - "name": "Ojooo Coin", - "network": "eth", - "shortcut": "OJX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OKB": { - "address": "0x75231F58b43240C9718Dd58B4967c5114342a86c", - "links": { - "Github": "https://github.com/okex/okberc20token", - "Homepage": "https://www.okex.com/" - }, - "marketcap_usd": 3080708053, - "name": "OKB", - "network": "eth", - "shortcut": "OKB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OLD_MKR": { - "address": "0xC66eA802717bFb9833400264Dd12c2bCeAa34a6d", - "links": { - "Github": "https://github.com/makerdao", - "Homepage": "https://makerdao.com" - }, - "marketcap_usd": 0, - "name": "MakerDAO", - "network": "eth", - "shortcut": "OLD_MKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OLE": { - "address": "0x9d9223436dDD466FC247e9dbbD20207e640fEf58", - "links": { - "Homepage": "http://www.olivecoin.co" - }, - "marketcap_usd": 0, - "name": "Olive", - "network": "eth", - "shortcut": "OLE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OLT": { - "address": "0x64A60493D888728Cf42616e034a0dfEAe38EFCF0", - "links": { - "Github": "https://github.com/Oneledger", - "Homepage": "https://oneledger.io" - }, - "marketcap_usd": 0, - "name": "OneLedger Token", - "network": "eth", - "shortcut": "OLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OMG": { - "address": "0xd26114cd6EE289AccF82350c8d8487fedB8A0C07", - "links": { - "Github": "https://github.com/omisego", - "Homepage": "https://omg.omise.co" - }, - "marketcap_usd": 243064600, - "name": "OmiseGO", - "network": "eth", - "shortcut": "OMG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OMT": { - "address": "0x047187e53477be70DBe8Ea5B799318f2e165052F", - "links": { - "Github": "https://github.com/OTCMAKER/OMT", - "Homepage": "https://www.otcmaker.com" - }, - "marketcap_usd": 0, - "name": "OTCMAKER Token", - "network": "eth", - "shortcut": "OMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OMX": { - "address": "0xB5DBC6D3cf380079dF3b27135664b6BCF45D1869", - "links": { - "Homepage": "https://shivom.io" - }, - "marketcap_usd": 0, - "name": "Shivom", - "network": "eth", - "shortcut": "OMX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ONEK": { - "address": "0xB23be73573bC7E03DB6e5dfc62405368716d28a8", - "links": { - "Homepage": "http://onek.one" - }, - "marketcap_usd": 0, - "name": "One K Token", - "network": "eth", - "shortcut": "ONEK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ONG": { - "address": "0xd341d1680Eeee3255b8C4c75bCCE7EB57f144dAe", - "links": { - "Github": "https://github.com/onGsocial", - "Homepage": "https://somee.social" - }, - "marketcap_usd": 0, - "name": "SoMee.Social", - "network": "eth", - "shortcut": "ONG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ONL": { - "address": "0x6863bE0e7CF7ce860A574760e9020D519a8bDC47", - "links": { - "Homepage": "https://on.live" - }, - "marketcap_usd": 0, - "name": "On.Live", - "network": "eth", - "shortcut": "ONL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ONOT": { - "address": "0xB31C219959E06f9aFBeB36b388a4BaD13E802725", - "links": { - "Homepage": "https://www.ono.chat" - }, - "marketcap_usd": 0, - "name": "ONO Token", - "network": "eth", - "shortcut": "ONOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OPQ": { - "address": "0x77599D2C6DB170224243e255e6669280F11F1473", - "links": { - "Github": "https://github.com/opacity", - "Homepage": "https://opacity.io" - }, - "marketcap_usd": 0, - "name": "Opacity", - "network": "eth", - "shortcut": "OPQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OPT": { - "address": "0x4355fC160f74328f9b383dF2EC589bB3dFd82Ba0", - "links": { - "Homepage": "https://opus-foundation.org" - }, - "marketcap_usd": 0, - "name": "Opus Foundation", - "network": "eth", - "shortcut": "OPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OPTI": { - "address": "0x832904863978b94802123106e6eB491BDF0Df928", - "links": { - "Homepage": "https://optitoken.io" - }, - "marketcap_usd": 0, - "name": "OptiToken", - "network": "eth", - "shortcut": "OPTI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OR": { - "address": "0x3fF9CeBbeAA7Bcc48a952a011A02a22a1FDd1C62", - "links": { - "Homepage": "https://ordertoken.store" - }, - "marketcap_usd": 0, - "name": "ORDER", - "network": "eth", - "shortcut": "OR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORBS": { - "address": "0xff56Cc6b1E6dEd347aA0B7676C85AB0B3D08B0FA", - "links": { - "Github": "https://github.com/orbs-network", - "Homepage": "https://orbs.com" - }, - "marketcap_usd": 102029850, - "name": "Orbs", - "network": "eth", - "shortcut": "ORBS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORCA": { - "address": "0x6F59e0461Ae5E2799F1fB3847f05a63B16d0DbF8", - "links": { - "Github": "https://github.com/orcaalliance", - "Homepage": "https://www.orcaalliance.eu" - }, - "marketcap_usd": 0, - "name": "ORCA Token", - "network": "eth", - "shortcut": "ORCA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORI": { - "address": "0xd2Fa8f92Ea72AbB35dBD6DECa57173d22db2BA49", - "links": { - "Homepage": "https://ori.network" - }, - "marketcap_usd": 0, - "name": "Origami", - "network": "eth", - "shortcut": "ORI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORN": { - "address": "0x8fB00FDeBb4E83f2C58b3bcD6732AC1B6A7b7221", - "links": { - "Github": "https://github.com/orionprotocol", - "Homepage": "https://orionprotocol.io/" - }, - "marketcap_usd": 0, - "name": "Orion Protocol", - "network": "eth", - "shortcut": "ORN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORS": { - "address": "0xEB9A4B185816C354dB92DB09cC3B50bE60b901b6", - "links": { - "Homepage": "https://www.originsport.io" - }, - "marketcap_usd": 867139, - "name": "Origin Sport", - "network": "eth", - "shortcut": "ORS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ORX": { - "address": "0x4e84A65B5664D33B67750771F8bEAeC458bD6729", - "links": { - "Github": "https://github.com/OrionixToken", - "Homepage": "https://orionix.io" - }, - "marketcap_usd": 0, - "name": "Orionix", - "network": "eth", - "shortcut": "ORX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OSPVS": { - "address": "0xFFA52DCE6Eb5695436BE96CA9b7Df63382e4c34d", - "links": { - "Homepage": "https://onyx.to/" - }, - "marketcap_usd": 0, - "name": "Token Onyx S&P 500 Short", - "network": "eth", - "shortcut": "OSPVS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OST": { - "address": "0x2C4e8f2D746113d0696cE89B35F0d8bF88E0AEcA", - "links": { - "Github": "https://github.com/OpenSTFoundation", - "Homepage": "https://simpletoken.org" - }, - "marketcap_usd": 406211, - "name": "Simple Token 'OST'", - "network": "eth", - "shortcut": "OST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OTN": { - "address": "0x881Ef48211982D01E2CB7092C915E647Cd40D85C", - "links": { - "Homepage": "https://otn.org" - }, - "marketcap_usd": 0, - "name": "Open Trading Network", - "network": "eth", - "shortcut": "OTN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OTO": { - "address": "0x028CE5EA3298a50c0D8a27b937b1F48Cf0d68b56", - "links": { - "Github": "https://github.com/OnTimeFoundation", - "Homepage": "https://www.ontimefoundation.org" - }, - "marketcap_usd": 0, - "name": "OnTime", - "network": "eth", - "shortcut": "OTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OUSD": { - "address": "0x2A8e1E676Ec238d8A992307B495b45B3fEAa5e86", - "links": { - "Github": "https://github.com/originprotocol", - "Homepage": "https://ousd.com" - }, - "marketcap_usd": 54479420, - "name": "Origin Dollar", - "network": "eth", - "shortcut": "OUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OWN": { - "address": "0x170b275CEd089FffAEBFe927F445a350ED9160DC", - "links": { - "Github": "https://github.com/owndata", - "Homepage": "https://owndata.network" - }, - "marketcap_usd": 0, - "name": "OWNDATA", - "network": "eth", - "shortcut": "OWN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OWT": { - "address": "0xC2494604e9DcEfa2A70dCEbf81e6D7BE064a334e", - "links": { - "Github": "https://github.com/openweb-network", - "Homepage": "https://openweb.network" - }, - "marketcap_usd": 0, - "name": "OpenWeb Token", - "network": "eth", - "shortcut": "OWT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:OXT": { - "address": "0x4575f41308EC1483f3d399aa9a2826d74Da13Deb", - "links": { - "Github": "https://github.com/orchidtechnologies/orchid", - "Homepage": "https://www.orchid.com" - }, - "marketcap_usd": 65851872, - "name": "Orchid", - "network": "eth", - "shortcut": "OXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:Ox Fina": { - "address": "0x65A15014964F2102Ff58647e16a16a6B9E14bCF6", - "links": { - "Github": "https://github.com/oxfina", - "Homepage": "https://oxfina.com" - }, - "marketcap_usd": 0, - "name": "Ox Fina", - "network": "eth", - "shortcut": "Ox Fina", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:P2PS": { - "address": "0x4527a3B4A8A150403090a99b87efFC96F2195047", - "links": { - "Github": "https://github.com/p2ps", - "Homepage": "https://p2psf.org" - }, - "marketcap_usd": 0, - "name": "P2P Solutions Foundation", - "network": "eth", - "shortcut": "P2PS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PAI": { - "address": "0xB9bb08AB7E9Fa0A1356bd4A39eC0ca267E03b0b3", - "links": { - "Homepage": "https://www.pchain.org" - }, - "marketcap_usd": 0, - "name": "PCHAIN", - "network": "eth", - "shortcut": "PAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PAL": { - "address": "0xfeDAE5642668f8636A11987Ff386bfd215F942EE", - "links": { - "Github": "https://github.com/policypalnet", - "Homepage": "https://www.policypal.network" - }, - "marketcap_usd": 0, - "name": "PolicyPal Network", - "network": "eth", - "shortcut": "PAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PARETO": { - "address": "0xea5f88E54d982Cbb0c441cde4E79bC305e5b43Bc", - "links": { - "Github": "https://github.com/ParetoNetwork", - "Homepage": "https://pareto.network" - }, - "marketcap_usd": 0, - "name": "PARETO", - "network": "eth", - "shortcut": "PARETO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PAT": { - "address": "0xF3b3Cad094B89392fcE5faFD40bC03b80F2Bc624", - "links": { - "Homepage": "https://patron-influencers.com" - }, - "marketcap_usd": 0, - "name": "Patron", - "network": "eth", - "shortcut": "PAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PATENTS": { - "address": "0x694404595e3075A942397F466AAcD462FF1a7BD0", - "links": { - "Homepage": "https://www.smartillions.ch" - }, - "marketcap_usd": 0, - "name": "PATENTS", - "network": "eth", - "shortcut": "PATENTS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PATH": { - "address": "0xF813F3902bBc00A6DCe378634d3B79D84F9803d7", - "links": { - "Github": "https://github.com/path-network-token", - "Homepage": "https://path.network" - }, - "marketcap_usd": 0, - "name": "PATH", - "network": "eth", - "shortcut": "PATH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PATR": { - "address": "0x9FbA684D77D2d6A1408C24b60A1f5534e71f5b75", - "links": { - "Github": "https://github.com/PatriotToken", - "Homepage": "http://patriotsilvertoken.com" - }, - "marketcap_usd": 0, - "name": "PATRIOT", - "network": "eth", - "shortcut": "PATR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PAXG": { - "address": "0x45804880De22913dAFE09f4980848ECE6EcbAf78", - "links": { - "Github": "https://github.com/paxosglobal/paxos-gold-contract", - "Homepage": "https://www.paxos.com/paxgold" - }, - "marketcap_usd": 487662967, - "name": "Paxos Gold", - "network": "eth", - "shortcut": "PAXG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PAY": { - "address": "0xB97048628DB6B661D4C2aA833e95Dbe1A905B280", - "links": { - "Homepage": "http://www.tenx.tech" - }, - "marketcap_usd": 3568855, - "name": "TenX", - "network": "eth", - "shortcut": "PAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PBL": { - "address": "0x55648De19836338549130B1af587F16beA46F66B", - "links": { - "Homepage": "https://publica.io" - }, - "marketcap_usd": 0, - "name": "PBL", - "network": "eth", - "shortcut": "PBL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PBT": { - "address": "0xF4c07b1865bC326A3c01339492Ca7538FD038Cc0", - "links": { - "Homepage": "http://primalbase.com/" - }, - "marketcap_usd": 0, - "name": "Primalbase Token (PBT)", - "network": "eth", - "shortcut": "PBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PCL": { - "address": "0x0F02e27745e3b6e9e1310d19469e2b5D7B5eC99A", - "links": { - "Github": "https://github.com/Peculium-Dev/", - "Homepage": "https://peculium.io" - }, - "marketcap_usd": 0, - "name": "Peculium", - "network": "eth", - "shortcut": "PCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PCLOLD": { - "address": "0x53148Bb4551707edF51a1e8d7A93698d18931225", - "links": { - "Github": "https://github.com/PeculiumPCL/Peculium", - "Homepage": "https://peculium.io" - }, - "marketcap_usd": 0, - "name": "PeculiumOLD", - "network": "eth", - "shortcut": "PCLOLD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PDATA": { - "address": "0x0db03B6CDe0B2d427C64a04FeAfd825938368f1F", - "links": { - "Github": "https://github.com/opiria-pdata/Pdata", - "Homepage": "https://opiria.io" - }, - "marketcap_usd": 0, - "name": "PDATA", - "network": "eth", - "shortcut": "PDATA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PEP": { - "address": "0xBb0eF9e617FADdf54B8D16e29046F72B4D3ec77F", - "links": { - "Homepage": "https://pepchain.io" - }, - "marketcap_usd": 0, - "name": "PEP Token", - "network": "eth", - "shortcut": "PEP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PESO": { - "address": "0x30FEF258d2728F9d1eDF038059c725FAf785697E", - "links": { - "Github": "https://github.com/pesotoken/PESO", - "Homepage": "http://pesoexchange.com" - }, - "marketcap_usd": 0, - "name": "PESOTOKEN", - "network": "eth", - "shortcut": "PESO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PET": { - "address": "0x5884969Ec0480556E11d119980136a4C17eDDEd1", - "links": { - "Github": "https://github.com/Pethereum", - "Homepage": "https://pethereum.org/" - }, - "marketcap_usd": 0, - "name": "PETHEREUM", - "network": "eth", - "shortcut": "PET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PETH": { - "address": "0xf53AD2c6851052A81B42133467480961B2321C09", - "links": { - "Homepage": "https://dai.makerdao.com/" - }, - "marketcap_usd": 0, - "name": "Pooled Ether", - "network": "eth", - "shortcut": "PETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PEXT": { - "address": "0x55c2A0C171D920843560594dE3d6EEcC09eFc098", - "links": { - "Homepage": "https://prime-ex.com" - }, - "marketcap_usd": 0, - "name": "PEX-Token", - "network": "eth", - "shortcut": "PEXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PFB": { - "address": "0x46760d2BF2F4dd5405646D9b2cE7B723EFE74a48", - "links": { - "Github": "https://github.com/PFB-Project", - "Homepage": "https://pfbproject.net/" - }, - "marketcap_usd": 0, - "name": "Penny For Bit", - "network": "eth", - "shortcut": "PFB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PFR": { - "address": "0x2FA32a39fc1c399E0Cc7B2935868f5165De7cE97", - "links": { - "Homepage": "https://payfair.io" - }, - "marketcap_usd": 0, - "name": "Payfair", - "network": "eth", - "shortcut": "PFR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PHI": { - "address": "0x13C2fab6354d3790D8ece4f0f1a3280b4A25aD96", - "links": { - "Homepage": "https://www.phitoken.io" - }, - "marketcap_usd": 0, - "name": "PHI Token", - "network": "eth", - "shortcut": "PHI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PICKLE": { - "address": "0x429881672B9AE42b8EbA0E26cD9C73711b891Ca5", - "links": { - "Homepage": "https://pickle.finance/" - }, - "marketcap_usd": 2689140, - "name": "Pickle Finance", - "network": "eth", - "shortcut": "PICKLE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PIPL": { - "address": "0xE64509F0bf07ce2d29A7eF19A8A9bc065477C1B4", - "links": { - "Homepage": "https://piplcoin.com" - }, - "marketcap_usd": 0, - "name": "PIPL Coin", - "network": "eth", - "shortcut": "PIPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PIT": { - "address": "0x0fF161071e627A0E6de138105C73970F86ca7922", - "links": { - "Homepage": "https://paypite.org" - }, - "marketcap_usd": 0, - "name": "Paypite v2", - "network": "eth", - "shortcut": "PIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PIX": { - "address": "0x8eFFd494eB698cc399AF6231fCcd39E08fd20B15", - "links": { - "Homepage": "https://www.lampix.co" - }, - "marketcap_usd": 0, - "name": "Lampix", - "network": "eth", - "shortcut": "PIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PIXIE": { - "address": "0x9318105460626e7fA58308FA4bcE40e4616F3565", - "links": { - "Homepage": "https://pixiedust.network" - }, - "marketcap_usd": 0, - "name": "Pixie Dust", - "network": "eth", - "shortcut": "PIXIE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PKG": { - "address": "0x02F2D4a04E6E01aCE88bD2Cd632875543b2eF577", - "links": { - "Homepage": "http://pkgtoken.io" - }, - "marketcap_usd": 79184, - "name": "PKG Token", - "network": "eth", - "shortcut": "PKG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PKT": { - "address": "0x2604FA406Be957E542BEb89E6754fCdE6815e83f", - "links": { - "Homepage": "https://playkey.io" - }, - "marketcap_usd": 65171, - "name": "Playkey", - "network": "eth", - "shortcut": "PKT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PLASMA": { - "address": "0x59416A25628A76b4730eC51486114c32E0B582A1", - "links": { - "Homepage": "https://plasma.io" - }, - "marketcap_usd": 0, - "name": "PLASMA", - "network": "eth", - "shortcut": "PLASMA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PLBT": { - "address": "0x0AfFa06e7Fbe5bC9a764C979aA66E8256A631f02", - "links": { - "Homepage": "https://polybius.io" - }, - "marketcap_usd": 0, - "name": "Polybius", - "network": "eth", - "shortcut": "PLBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PLR": { - "address": "0xe3818504c1B32bF1557b16C238B2E01Fd3149C17", - "links": { - "Github": "https://github.com/twentythirty/PillarToken", - "Homepage": "https://www.pillarproject.io" - }, - "marketcap_usd": 1387534, - "name": "Pillar Project", - "network": "eth", - "shortcut": "PLR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PLS": { - "address": "0xe43ac1714F7394173b15E7CfF31A63d523Ce4fB9", - "links": { - "Github": "https://github.com/bitsuperlab", - "Homepage": "https://dacplay.org" - }, - "marketcap_usd": 0, - "name": "DACPLAY Token", - "network": "eth", - "shortcut": "PLS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PLU": { - "address": "0xD8912C10681D8B21Fd3742244f44658dBA12264E", - "links": { - "Homepage": "https://plutus.it" - }, - "marketcap_usd": 18172960, - "name": "Pluton", - "network": "eth", - "shortcut": "PLU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PMA": { - "address": "0x846C66cf71C43f80403B51fE3906B3599D63336f", - "links": { - "Homepage": "https://pumapay.io" - }, - "marketcap_usd": 420840, - "name": "PumaPay", - "network": "eth", - "shortcut": "PMA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PMNT": { - "address": "0x81b4D08645DA11374a03749AB170836E4e539767", - "links": { - "Homepage": "https://paymon.org" - }, - "marketcap_usd": 0, - "name": "Paymon", - "network": "eth", - "shortcut": "PMNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PNK": { - "address": "0x93ED3FBe21207Ec2E8f2d3c3de6e058Cb73Bc04d", - "links": { - "Github": "https://github.com/kleros", - "Homepage": "https://kleros.io" - }, - "marketcap_usd": 18057635, - "name": "Pinakion", - "network": "eth", - "shortcut": "PNK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POE": { - "address": "0x0e0989b1f9B8A38983c2BA8053269Ca62Ec9B195", - "links": { - "Homepage": "https://po.et" - }, - "marketcap_usd": 66098, - "name": "Po.et Tokens", - "network": "eth", - "shortcut": "POE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POIN": { - "address": "0x43F6a1BE992deE408721748490772B15143CE0a7", - "links": { - "Homepage": "https://potatoin.foundation" - }, - "marketcap_usd": 0, - "name": "Potatoin", - "network": "eth", - "shortcut": "POIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POLL": { - "address": "0x705EE96c1c160842C92c1aeCfCFfccc9C412e3D9", - "links": { - "Homepage": "https://clearpoll.com" - }, - "marketcap_usd": 0, - "name": "ClearPoll", - "network": "eth", - "shortcut": "POLL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POLY": { - "address": "0x9992eC3cF6A55b00978cdDF2b27BC6882d88D1eC", - "links": { - "Homepage": "https://polymath.network" - }, - "marketcap_usd": 178335520, - "name": "Polymath Network", - "network": "eth", - "shortcut": "POLY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POOL": { - "address": "0x779B7b713C86e3E6774f5040D9cCC2D43ad375F8", - "links": { - "Homepage": "http://stakepool.co" - }, - "marketcap_usd": 0, - "name": "Stake Pool", - "network": "eth", - "shortcut": "POOL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POP": { - "address": "0x5D858bcd53E085920620549214a8b27CE2f04670", - "links": { - "Github": "https://github.com/popchest", - "Homepage": "https://www.thepopnetwork.org" - }, - "marketcap_usd": 0, - "name": "POP Network Token", - "network": "eth", - "shortcut": "POP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POS": { - "address": "0xEe609fE292128Cad03b786DBb9Bc2634Ccdbe7fC", - "links": { - "Github": "https://github.com/PoSToken", - "Homepage": "https://postoken.org" - }, - "marketcap_usd": 0, - "name": "PoSToken", - "network": "eth", - "shortcut": "POS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:POWR": { - "address": "0x595832F8FC6BF59c85C527fEC3740A1b7a361269", - "links": { - "Homepage": "https://powerledger.io" - }, - "marketcap_usd": 104709098, - "name": "PowerLedger", - "network": "eth", - "shortcut": "POWR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PPP": { - "address": "0xc42209aCcC14029c1012fB5680D95fBd6036E2a0", - "links": { - "Homepage": "https://www.paypie.com" - }, - "marketcap_usd": 0, - "name": "PayPie", - "network": "eth", - "shortcut": "PPP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PPT": { - "address": "0xd4fa1460F537bb9085d22C7bcCB5DD450Ef28e3a", - "links": { - "Github": "https://github.com/Bitpopulous", - "Homepage": "https://populous.co" - }, - "marketcap_usd": 4787929, - "name": "Populous", - "network": "eth", - "shortcut": "PPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRE": { - "address": "0x88A3E4F35D64aAD41A6d4030ac9AFE4356cB84fA", - "links": { - "Homepage": "https://presearch.io" - }, - "marketcap_usd": 0, - "name": "Presearch", - "network": "eth", - "shortcut": "PRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRG": { - "address": "0x7728dFEF5aBd468669EB7f9b48A7f70a501eD29D", - "links": { - "Github": "https://github.com/paragon-coin/token", - "Homepage": "https://paragoncoin.com" - }, - "marketcap_usd": 0, - "name": "Paragon", - "network": "eth", - "shortcut": "PRG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRIX": { - "address": "0x3ADfc4999F77D04c8341BAC5F3A76f58DfF5B37A", - "links": { - "Homepage": "https://privatix.io" - }, - "marketcap_usd": 45253, - "name": "Privatix", - "network": "eth", - "shortcut": "PRIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRL": { - "address": "0x1844b21593262668B7248d0f57a220CaaBA46ab9", - "links": { - "Github": "https://github.com/oysterprotocol", - "Homepage": "https://oyster.ws" - }, - "marketcap_usd": 0, - "name": "Oyster Pearl", - "network": "eth", - "shortcut": "PRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRON": { - "address": "0xA3149E0fA0061A9007fAf307074cdCd290f0e2Fd", - "links": { - "Homepage": "https://proncoin.io" - }, - "marketcap_usd": 0, - "name": "PronCoin", - "network": "eth", - "shortcut": "PRON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PROPS": { - "address": "0x6fe56C0bcdD471359019FcBC48863d6c3e9d4F41", - "links": { - "Github": "https://github.com/propsproject", - "Homepage": "https://propsproject.com" - }, - "marketcap_usd": 824153, - "name": "Props", - "network": "eth", - "shortcut": "PROPS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRS": { - "address": "0x163733bcc28dbf26B41a8CfA83e369b5B3af741b", - "links": { - "Github": "https://github.com/Neurone/persians", - "Homepage": "http://persians.network" - }, - "marketcap_usd": 0, - "name": "Persians", - "network": "eth", - "shortcut": "PRS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PRSP": { - "address": "0x0C04d4f331DA8dF75f9E2e271E3f3F1494C66C36", - "links": { - "Homepage": "http://www.prsp.me" - }, - "marketcap_usd": 0, - "name": "PRSP", - "network": "eth", - "shortcut": "PRSP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PSDN": { - "address": "0x5F85c60187aB233Ca6e750731D15e7eFd061fBdE", - "links": { - "Homepage": "http://poseidonsbazaar.com" - }, - "marketcap_usd": 0, - "name": "Poseidon", - "network": "eth", - "shortcut": "PSDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PSK": { - "address": "0x1c5F43710a1776b0Ea7191b7Ead75D4B98D69858", - "links": { - "Github": "https://github.com/poolofstake/PSK", - "Homepage": "https://www.poolofstake.io" - }, - "marketcap_usd": 0, - "name": "Pool of Stake Master Token", - "network": "eth", - "shortcut": "PSK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PST": { - "address": "0x5d4ABC77B8405aD177d8ac6682D584ecbFd46CEc", - "links": { - "Homepage": "https://primas.io" - }, - "marketcap_usd": 659916, - "name": "Primas", - "network": "eth", - "shortcut": "PST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PT": { - "address": "0x66497A283E0a007bA3974e837784C6AE323447de", - "links": { - "Github": "https://github.com/porntoken/smart_contract", - "Homepage": "https://www.porntoken.io" - }, - "marketcap_usd": 0, - "name": "PornToken", - "network": "eth", - "shortcut": "PT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PTC": { - "address": "0x2a8E98e256f32259b5E5Cb55Dd63C8e891950666", - "links": { - "Github": "https://github.com/ParrotCoin", - "Homepage": "http://parrotcoin.club" - }, - "marketcap_usd": 0, - "name": "ParrotCoin", - "network": "eth", - "shortcut": "PTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PTOY": { - "address": "0x8Ae4BF2C33a8e667de34B54938B0ccD03Eb8CC06", - "links": { - "Homepage": "https://patientory.com" - }, - "marketcap_usd": 483007, - "name": "Patientory", - "network": "eth", - "shortcut": "PTOY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PTT": { - "address": "0x4689a4e169eB39cC9078C0940e21ff1Aa8A39B9C", - "links": { - "Homepage": "https://www.proton.global" - }, - "marketcap_usd": 0, - "name": "Proton Token", - "network": "eth", - "shortcut": "PTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PTWO": { - "address": "0x5512e1D6A7BE424b4323126B4f9E86D023F95764", - "links": { - "Github": "https://github.com/porntoken/smart_contract", - "Homepage": "https://www.porntoken.io" - }, - "marketcap_usd": 0, - "name": "PornTokenV2", - "network": "eth", - "shortcut": "PTWO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PUC": { - "address": "0xEf6B4cE8C9Bc83744fbcdE2657b32eC18790458A", - "links": { - "Github": "https://github.com/pourcoin/pourcoin-PUC/projects", - "Homepage": "http://price-s.info" - }, - "marketcap_usd": 0, - "name": "Pour Coin", - "network": "eth", - "shortcut": "PUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PURC": { - "address": "0xe25ff6Eb959BCE67975778e46A47750C243B6B99", - "links": { - "Github": "https://github.com/seanyc99/PureCarbon-Smart-Contract", - "Homepage": "https://purecarbon.io" - }, - "marketcap_usd": 0, - "name": "PureCarbon", - "network": "eth", - "shortcut": "PURC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PUSSY": { - "address": "0x9196E18Bc349B1F64Bc08784eaE259525329a1ad", - "links": { - "Github": "https://github.com/Pussy-Financial", - "Homepage": "https://pussy.financial" - }, - "marketcap_usd": 0, - "name": "Pussy Financial", - "network": "eth", - "shortcut": "PUSSY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PXG": { - "address": "0x47e67BA66b0699500f18A53F94E2b9dB3D47437e", - "links": { - "Github": "https://github.com/playgame-global", - "Homepage": "https://its.playgame.com" - }, - "marketcap_usd": 200007, - "name": "PlayGame", - "network": "eth", - "shortcut": "PXG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PXT": { - "address": "0xc14830E53aA344E8c14603A91229A0b925b0B262", - "links": { - "Homepage": "https://populous.co" - }, - "marketcap_usd": 0, - "name": "Populous XBRL Token (PXT)", - "network": "eth", - "shortcut": "PXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PYLNT": { - "address": "0x7703C35CfFdC5CDa8D27aa3df2F9ba6964544b6e", - "links": { - "Homepage": "https://pylon-network.org" - }, - "marketcap_usd": 0, - "name": "Pylon Network", - "network": "eth", - "shortcut": "PYLNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:PYN": { - "address": "0x0142C3B2fC51819B5aF5dFc4AA52Df9722790851", - "links": { - "Github": "https://github.com/PaycentGlobal", - "Homepage": "https://paycent.com/" - }, - "marketcap_usd": 0, - "name": "Paycentos", - "network": "eth", - "shortcut": "PYN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QASH": { - "address": "0x618E75Ac90b12c6049Ba3b27f5d5F8651b0037F6", - "links": { - "Homepage": "https://liquid.plus" - }, - "marketcap_usd": 9192048, - "name": "QASH", - "network": "eth", - "shortcut": "QASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QAU": { - "address": "0x671AbBe5CE652491985342e85428EB1b07bC6c64", - "links": { - "Homepage": "http://www.quantumproject.org" - }, - "marketcap_usd": 0, - "name": "QAU", - "network": "eth", - "shortcut": "QAU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QBX": { - "address": "0x2467AA6B5A2351416fD4C3DeF8462d841feeecEC", - "links": { - "Github": "https://github.com/qiibee", - "Homepage": "https://www.qiibee.com" - }, - "marketcap_usd": 0, - "name": "qiibeeToken", - "network": "eth", - "shortcut": "QBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QDT": { - "address": "0x9Adc7710E9d1b29d8a78c04d52D32532297C2Ef3", - "links": { - "Github": "https://github.com/quadrans", - "Homepage": "https://quadrans.io" - }, - "marketcap_usd": 0, - "name": "Quadrans Token", - "network": "eth", - "shortcut": "QDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QKC": { - "address": "0xEA26c4aC16D4a5A106820BC8AEE85fd0b7b2b664", - "links": { - "Homepage": "https://quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "network": "eth", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QNT": { - "address": "0x4a220E6096B25EADb88358cb44068A3248254675", - "links": { - "Github": "https://github.com/quantnetwork", - "Homepage": "https://www.quant.network/" - }, - "marketcap_usd": 1530947563, - "name": "Quant", - "network": "eth", - "shortcut": "QNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QRG": { - "address": "0xFFAA5ffc455d9131f8A2713A741fD1960330508B", - "links": { - "Homepage": "http://qrg-stamps.com/" - }, - "marketcap_usd": 0, - "name": "QRG", - "network": "eth", - "shortcut": "QRG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QRL": { - "address": "0x697beac28B09E122C4332D163985e8a73121b97F", - "links": { - "Github": "https://github.com/theQRL", - "Homepage": "https://theqrl.org" - }, - "marketcap_usd": 0, - "name": "QRL", - "network": "eth", - "shortcut": "QRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QSP": { - "address": "0x99ea4dB9EE77ACD40B119BD1dC4E33e1C070b80d", - "links": { - "Github": "https://github.com/quantstamp", - "Homepage": "https://quantstamp.com/" - }, - "marketcap_usd": 11601312, - "name": "Quantstamp Token", - "network": "eth", - "shortcut": "QSP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QTQ": { - "address": "0x2C3C1F05187dBa7A5f2Dd47Dca57281C4d4F183F", - "links": { - "Github": "https://github.com/TiiQu-Network/TiiQu-Network", - "Homepage": "http://tiiqu.com" - }, - "marketcap_usd": 0, - "name": "TiiQu's Q Token", - "network": "eth", - "shortcut": "QTQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QTUM": { - "address": "0x9a642d6b3368ddc662CA244bAdf32cDA716005BC", - "links": { - "Github": "https://github.com/qtumproject", - "Homepage": "https://qtum.org/" - }, - "marketcap_usd": 0, - "name": "Qtum", - "network": "eth", - "shortcut": "QTUM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:QUN": { - "address": "0x264Dc2DedCdcbb897561A57CBa5085CA416fb7b4", - "links": { - "Homepage": "https://qunqun.io" - }, - "marketcap_usd": 0, - "name": "QunQun", - "network": "eth", - "shortcut": "QUN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:R": { - "address": "0x48f775EFBE4F5EcE6e0DF2f7b5932dF56823B990", - "links": { - "Homepage": "https://revain.org" - }, - "marketcap_usd": 0, - "name": "Revain", - "network": "eth", - "shortcut": "R", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RAE": { - "address": "0xE5a3229CCb22b6484594973A03a3851dCd948756", - "links": { - "Github": "https://github.com/rokfin/eth-contracts", - "Homepage": "https://www.raetoken.org" - }, - "marketcap_usd": 7985545, - "name": "RAE Token", - "network": "eth", - "shortcut": "RAE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RAI": { - "address": "0x03ab458634910AaD20eF5f1C8ee96F1D6ac54919", - "links": { - "Github": "https://github.com/reflexer-labs/", - "Homepage": "https://reflexer.finance/" - }, - "marketcap_usd": 6622639, - "name": "Rai Reflex Index", - "network": "eth", - "shortcut": "RAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RAO": { - "address": "0x45eDb535942a8C84D9f4b5D37e1b25F91Ea4804c", - "links": { - "Github": "https://github.com/RadioYoFM/ICO_smartcontract/", - "Homepage": "https://rao.radioyo.fm" - }, - "marketcap_usd": 0, - "name": "RadioYo", - "network": "eth", - "shortcut": "RAO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RATING": { - "address": "0xE8663A64A96169ff4d95b4299E7ae9a76b905B31", - "links": { - "Homepage": "http://token.dprating.com" - }, - "marketcap_usd": 344016, - "name": "DPRating", - "network": "eth", - "shortcut": "RATING", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RBLX": { - "address": "0xFc2C4D8f95002C14eD0a7aA65102Cac9e5953b5E", - "links": { - "Github": "https://github.com/rublixdev", - "Homepage": "https://rublix.io/" - }, - "marketcap_usd": 535673, - "name": "Rublix", - "network": "eth", - "shortcut": "RBLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RBX": { - "address": "0x8254e26e453EB5aBd29B3c37AC9E8Da32E5d3299", - "links": { - "Homepage": "https://rbx.ae/" - }, - "marketcap_usd": 0, - "name": "RBX", - "network": "eth", - "shortcut": "RBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RCN": { - "address": "0xF970b8E36e23F7fC3FD752EeA86f8Be8D83375A6", - "links": { - "Github": "https://github.com/ripio/rcn-token", - "Homepage": "https://ripiocredit.network" - }, - "marketcap_usd": 1108878, - "name": "Ripio Credit Network", - "network": "eth", - "shortcut": "RCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RDN": { - "address": "0x255Aa6DF07540Cb5d3d297f0D0D4D84cb52bc8e6", - "links": { - "Github": "https://github.com/raiden-network/raiden/", - "Homepage": "https://raiden.network" - }, - "marketcap_usd": 2880243, - "name": "Raiden Network", - "network": "eth", - "shortcut": "RDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RDV": { - "address": "0xd967d9F941CD316Ab238d3EE761F80b7cAec7819", - "links": { - "Github": "https://github.com/Rendezvous-Paradise", - "Homepage": "https://www.rendezvous.vip" - }, - "marketcap_usd": 0, - "name": "Rendezvous", - "network": "eth", - "shortcut": "RDV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REA": { - "address": "0x767bA2915EC344015a7938E3eEDfeC2785195D05", - "links": { - "Homepage": "https://www.realisto.io" - }, - "marketcap_usd": 0, - "name": "Realisto", - "network": "eth", - "shortcut": "REA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REAL": { - "address": "0x9214eC02CB71CbA0ADA6896b8dA260736a67ab10", - "links": { - "Homepage": "https://www.real.markets" - }, - "marketcap_usd": 0, - "name": "Real Estate Asset Ledger", - "network": "eth", - "shortcut": "REAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REBL": { - "address": "0x5F53f7A8075614b699Baad0bC2c899f4bAd8FBBF", - "links": { - "Homepage": "https://www.rebellious.io" - }, - "marketcap_usd": 0, - "name": "Rebellious", - "network": "eth", - "shortcut": "REBL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RED": { - "address": "0x76960Dccd5a1fe799F7c29bE9F19ceB4627aEb2f", - "links": { - "Github": "https://github.com/red", - "Homepage": "https://ico.red-lang.org" - }, - "marketcap_usd": 293525, - "name": "Red Community Token", - "network": "eth", - "shortcut": "RED", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REDC": { - "address": "0xB563300A3BAc79FC09B93b6F84CE0d4465A2AC27", - "links": { - "Github": "https://github.com/Redcabllc", - "Homepage": "https://redcab.io" - }, - "marketcap_usd": 0, - "name": "RedCab", - "network": "eth", - "shortcut": "REDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REEF": { - "address": "0xFE3E6a25e6b192A42a44ecDDCd13796471735ACf", - "links": { - "Github": "http://github.com/reef-defi", - "Homepage": "http://reef.finance" - }, - "marketcap_usd": 70777959, - "name": "Reef Finance", - "network": "eth", - "shortcut": "REEF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REF": { - "address": "0x89303500a7Abfb178B274FD89F2469C264951e1f", - "links": { - "Homepage": "https://reftoken.io" - }, - "marketcap_usd": 0, - "name": "RefToken", - "network": "eth", - "shortcut": "REF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REM": { - "address": "0x83984d6142934bb535793A82ADB0a46EF0F66B6d", - "links": { - "Homepage": "https://remme.io" - }, - "marketcap_usd": 152526, - "name": "Remme", - "network": "eth", - "shortcut": "REM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REMI": { - "address": "0x13cb85823f78Cff38f0B0E90D3e975b8CB3AAd64", - "links": { - "Github": "https://github.com/remiit", - "Homepage": "https://remiit.io" - }, - "marketcap_usd": 0, - "name": "REMI", - "network": "eth", - "shortcut": "REMI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REN": { - "address": "0x408e41876cCCDC0F92210600ef50372656052a38", - "links": { - "Github": "https://github.com/renproject", - "Homepage": "https://renproject.io/" - }, - "marketcap_usd": 97699774, - "name": "Republic Token", - "network": "eth", - "shortcut": "REN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REP": { - "address": "0x1985365e9f78359a9B6AD760e32412f4a445E862", - "links": { - "Homepage": "https://augur.net" - }, - "marketcap_usd": 100020697, - "name": "Augur", - "network": "eth", - "shortcut": "REP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REPv2": { - "address": "0x221657776846890989a759BA2973e427DfF5C9bB", - "links": { - "Homepage": "https://augur.net" - }, - "marketcap_usd": 0, - "name": "Reputation", - "network": "eth", - "shortcut": "REPv2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REQ": { - "address": "0x8f8221aFbB33998d8584A2B05749bA73c37a938a", - "links": { - "Homepage": "https://request.network" - }, - "marketcap_usd": 113609078, - "name": "Request Network", - "network": "eth", - "shortcut": "REQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REV": { - "address": "0x2ef52Ed7De8c5ce03a4eF0efbe9B7450F2D7Edc9", - "links": { - "Github": "https://github.com/Revain", - "Homepage": "https://revain.org" - }, - "marketcap_usd": 50618632, - "name": "Revain", - "network": "eth", - "shortcut": "REV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:REX": { - "address": "0xf05a9382A4C3F29E2784502754293D88b835109C", - "links": { - "Github": "https://github.com/rexmls/RexToken", - "Homepage": "https://imbrex.io" - }, - "marketcap_usd": 0, - "name": "imbrex", - "network": "eth", - "shortcut": "REX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RFR": { - "address": "0xd0929d411954c47438dc1d871dd6081F5C5e149c", - "links": { - "Homepage": "https://refereum.com" - }, - "marketcap_usd": 33221299, - "name": "Refereum", - "network": "eth", - "shortcut": "RFR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RHOC": { - "address": "0x168296bb09e24A88805CB9c33356536B980D3fC5", - "links": { - "Homepage": "https://www.rchain.coop" - }, - "marketcap_usd": 0, - "name": "RChain", - "network": "eth", - "shortcut": "RHOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RIPT": { - "address": "0xdd007278B667F6bef52fD0a4c23604aA1f96039a", - "links": { - "Github": "https://github.com/riptidecoin/riptide-coin", - "Homepage": "https://riptidecoin.com" - }, - "marketcap_usd": 0, - "name": "RiptideCoin", - "network": "eth", - "shortcut": "RIPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RIYA": { - "address": "0x0b1724cc9FDA0186911EF6a75949e9c0d3F0f2F3", - "links": { - "Homepage": "http://etheriya.com" - }, - "marketcap_usd": 0, - "name": "Etheriya", - "network": "eth", - "shortcut": "RIYA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RLC": { - "address": "0x607F4C5BB672230e8672085532f7e901544a7375", - "links": { - "Homepage": "http://iex.ec/" - }, - "marketcap_usd": 154000623, - "name": "IEx.ec", - "network": "eth", - "shortcut": "RLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RLT": { - "address": "0xcCeD5B8288086BE8c38E23567e684C3740be4D48", - "links": { - "Github": "https://github.com/Smartroulette", - "Homepage": "https://smartplay.tech" - }, - "marketcap_usd": 0, - "name": "RouletteToken", - "network": "eth", - "shortcut": "RLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RLTY": { - "address": "0xbe99B09709fc753b09BCf557A992F6605D5997B0", - "links": { - "Homepage": "http://www.smartrealty.io" - }, - "marketcap_usd": 0, - "name": "SMARTRealty", - "network": "eth", - "shortcut": "RLTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RLX": { - "address": "0x4A42d2c580f83dcE404aCad18dab26Db11a1750E", - "links": { - "Homepage": "http://www.relex.io" - }, - "marketcap_usd": 0, - "name": "Relex", - "network": "eth", - "shortcut": "RLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RMESH": { - "address": "0x8D5682941cE456900b12d47ac06a88b47C764CE1", - "links": { - "Github": "https://github.com/rightmesh", - "Homepage": "https://www.rightmesh.io/" - }, - "marketcap_usd": 0, - "name": "RightMesh Token", - "network": "eth", - "shortcut": "RMESH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RNDR": { - "address": "0x0996bFb5D057faa237640E2506BE7B4f9C46de0B", - "links": { - "Homepage": "https://rendertoken.com" - }, - "marketcap_usd": 0, - "name": "Render Token", - "network": "eth", - "shortcut": "RNDR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RNT": { - "address": "0xFF603F43946A3A28DF5E6A73172555D8C8b02386", - "links": { - "Homepage": "https://www.oneroot.io/en" - }, - "marketcap_usd": 532562, - "name": "OneRoot Network", - "network": "eth", - "shortcut": "RNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RNTB": { - "address": "0x1FE70bE734e473e5721ea57C8B5B01e6Caa52686", - "links": { - "Homepage": "https://bitrent.io" - }, - "marketcap_usd": 0, - "name": "BitRent", - "network": "eth", - "shortcut": "RNTB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ROCK": { - "address": "0xA40106134c5bF4c41411554e6db99B95A15ed9d8", - "links": { - "Github": "https://github.com/rocketico", - "Homepage": "https://rocketico.io" - }, - "marketcap_usd": 0, - "name": "Rocket Token", - "network": "eth", - "shortcut": "ROCK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ROCK2": { - "address": "0xC16b542ff490e01fcc0DC58a60e1EFdc3e357cA6", - "links": { - "Homepage": "https://icerockmining.io" - }, - "marketcap_usd": 0, - "name": "ICE ROCK MINING", - "network": "eth", - "shortcut": "ROCK2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ROCK2PAY": { - "address": "0x0E3de3B0E3D617FD8D1D8088639bA877feb4d742", - "links": { - "Homepage": "https://icerockmining.io" - }, - "marketcap_usd": 0, - "name": "ICE ROCK MINING", - "network": "eth", - "shortcut": "ROCK2PAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ROK": { - "address": "0xc9De4B7F0C3d991e967158E4D4bFA4b51Ec0b114", - "links": { - "Homepage": "https://rockchain.org" - }, - "marketcap_usd": 0, - "name": "Rocketchain", - "network": "eth", - "shortcut": "ROK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ROOBEE": { - "address": "0xA31B1767e09f842ECFd4bc471Fe44F830E3891AA", - "links": { - "Homepage": "https://roobee.io/" - }, - "marketcap_usd": 4479943, - "name": "ROOBEE", - "network": "eth", - "shortcut": "ROOBEE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RPE": { - "address": "0xCcc85AA8999505d6f886A32da4a107BBe0D1dE9E", - "links": { - "Github": "https://github.com/repetoken", - "Homepage": "http://repetoken.com" - }, - "marketcap_usd": 0, - "name": "REPE", - "network": "eth", - "shortcut": "RPE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RPL": { - "address": "0xB4EFd85c19999D84251304bDA99E90B92300Bd93", - "links": { - "Homepage": "https://www.rocketpool.net" - }, - "marketcap_usd": 0, - "name": "Rocket Pool", - "network": "eth", - "shortcut": "RPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RSR": { - "address": "0x320623b8E4fF03373931769A31Fc52A4E78B5d70", - "links": { - "Github": "https://github.com/reserve-protocol/rsr-mainnet", - "Homepage": "https://reserve.org" - }, - "marketcap_usd": 234795022, - "name": "Reserve Rights", - "network": "eth", - "shortcut": "RSR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RTB": { - "address": "0xEC491c1088Eae992B7A214efB0a266AD0927A72A", - "links": { - "Homepage": "https://ab-chain.com" - }, - "marketcap_usd": 0, - "name": "AB-Chain RTB", - "network": "eth", - "shortcut": "RTB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RTC": { - "address": "0x7A5599B97E8c4abB5dd06EBA0E9d1F75AF818DB9", - "links": { - "Github": "http://www.github.com/osmoticio", - "Homepage": "http://osmotic.io" - }, - "marketcap_usd": 0, - "name": "OSMOTIC TOKEN", - "network": "eth", - "shortcut": "RTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RTH": { - "address": "0x3FD8f39A962eFDA04956981C31AB89FAB5FB8bC8", - "links": { - "Homepage": "https://www.rotharium.io" - }, - "marketcap_usd": 3022419, - "name": "Rotharium", - "network": "eth", - "shortcut": "RTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RTN": { - "address": "0x54b293226000ccBFC04DF902eEC567CB4C35a903", - "links": { - "Github": "https://github.com/Ridercoin2/RiderCoin/blob/master/README.md", - "Homepage": "http://ridertoken.com" - }, - "marketcap_usd": 0, - "name": "RiderToken", - "network": "eth", - "shortcut": "RTN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RUFF": { - "address": "0xf278c1CA969095ffddDED020290cf8B5C424AcE2", - "links": { - "Homepage": "http://ruffchain.com" - }, - "marketcap_usd": 349118, - "name": "Ruff", - "network": "eth", - "shortcut": "RUFF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RUNE": { - "address": "0xdEE02D94be4929d26f67B64Ada7aCf1914007F10", - "links": { - "Github": "https://github.com/thorchain", - "Homepage": "https://thorchain.org" - }, - "marketcap_usd": 0, - "name": "Rune", - "network": "eth", - "shortcut": "RUNE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RVL": { - "address": "0x41f615E24fAbd2b097a320E9E6c1f448cb40521c", - "links": { - "Homepage": "https://www.r-evolutioncoin.com" - }, - "marketcap_usd": 0, - "name": "RVL", - "network": "eth", - "shortcut": "RVL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RVT": { - "address": "0x3d1BA9be9f66B8ee101911bC36D3fB562eaC2244", - "links": { - "Homepage": "https://rivetzintl.com" - }, - "marketcap_usd": 15562, - "name": "Rivetz", - "network": "eth", - "shortcut": "RVT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:RYLT": { - "address": "0xd30a2e9347Ad48Ea208ee563a9CdfD80E962a727", - "links": { - "Github": "https://github.com/RoyaltyCOINx", - "Homepage": "http://royaltycoin.com" - }, - "marketcap_usd": 0, - "name": "RoyaltyCOIN", - "network": "eth", - "shortcut": "RYLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:S-A-PAT": { - "address": "0x1EC8fE51a9B6A3a6C427D17d9ECC3060fbc4a45c", - "links": { - "Homepage": "https://www.smartillions.ch" - }, - "marketcap_usd": 0, - "name": "S-A-PAT", - "network": "eth", - "shortcut": "S-A-PAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:S-ETH": { - "address": "0x3eb91D237e491E0DEE8582c402D85CB440fb6b54", - "links": { - "Homepage": "https://www.smartillions.ch" - }, - "marketcap_usd": 0, - "name": "S-ETH", - "network": "eth", - "shortcut": "S-ETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SAC": { - "address": "0xabC1280A0187a2020cC675437aed400185F86Db6", - "links": { - "Homepage": "https://www.sachain.net" - }, - "marketcap_usd": 0, - "name": "Smart Application Chain", - "network": "eth", - "shortcut": "SAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SAI": { - "address": "0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359", - "links": { - "Github": "https://github.com/makerdao", - "Homepage": "https://makerdao.com" - }, - "marketcap_usd": 0, - "name": "Dai Stablecoin v1.0", - "network": "eth", - "shortcut": "SAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SALT": { - "address": "0x4156D3342D5c385a87D264F90653733592000581", - "links": { - "Homepage": "https://saltlending.com" - }, - "marketcap_usd": 6351019, - "name": "Salt Lending Token", - "network": "eth", - "shortcut": "SALT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SAN": { - "address": "0x7C5A0CE9267ED19B22F8cae653F198e3E8daf098", - "links": { - "Homepage": "https://santiment.net" - }, - "marketcap_usd": 3377746, - "name": "Santiment", - "network": "eth", - "shortcut": "SAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SCANDI": { - "address": "0x78fE18e41f436e1981a3a60D1557c8a7a9370461", - "links": { - "Homepage": "https://scandiweb.com" - }, - "marketcap_usd": 0, - "name": "Scandiweb Coin", - "network": "eth", - "shortcut": "SCANDI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SCL": { - "address": "0xd7631787B4dCc87b1254cfd1e5cE48e96823dEe8", - "links": { - "Homepage": "https://ico.nexus.social" - }, - "marketcap_usd": 0, - "name": "SocialCoin", - "network": "eth", - "shortcut": "SCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SCRL": { - "address": "0x24DCc881E7Dd730546834452F21872D5cb4b5293", - "links": { - "Homepage": "https://www.scroll.network" - }, - "marketcap_usd": 0, - "name": "SCRL", - "network": "eth", - "shortcut": "SCRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SEELE": { - "address": "0xB1eeF147028E9f480DbC5ccaA3277D417D1b85F0", - "links": { - "Homepage": "http://seele.pro" - }, - "marketcap_usd": 0, - "name": "Seele", - "network": "eth", - "shortcut": "SEELE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SELF": { - "address": "0x67ab11058eF23D0a19178f61A050D3c38F81Ae21", - "links": { - "Github": "https://github.com/selftoken-projects", - "Homepage": "https://selftoken.co/" - }, - "marketcap_usd": 0, - "name": "SELF TOKEN", - "network": "eth", - "shortcut": "SELF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SENC": { - "address": "0xA13f0743951B4f6E3e3AA039f682E17279f52bc3", - "links": { - "Homepage": "https://www.sentinel-chain.org" - }, - "marketcap_usd": 90109, - "name": "Sentinel Chain", - "network": "eth", - "shortcut": "SENC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SENSE": { - "address": "0x6745fAB6801e376cD24F03572B9C9B0D4EdDDCcf", - "links": { - "Homepage": "https://sensay.it" - }, - "marketcap_usd": 0, - "name": "Sensay", - "network": "eth", - "shortcut": "SENSE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SENT": { - "address": "0xa44E5137293E855B1b7bC7E2C6f8cD796fFCB037", - "links": { - "Homepage": "https://sentinel.co" - }, - "marketcap_usd": 0, - "name": "SENTinel", - "network": "eth", - "shortcut": "SENT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SET": { - "address": "0xe06eda7435bA749b047380CEd49121ddE93334Ae", - "links": { - "Github": "https://github.com/SydEthereum/meetup-token#meetup-token", - "Homepage": "http://sydeth.com" - }, - "marketcap_usd": 0, - "name": "SET", - "network": "eth", - "shortcut": "SET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SETS": { - "address": "0x04E0Af0af1b7f0023c6B12af5a94Df59B0e8cF59", - "links": { - "Homepage": "https://wwww.sensitrust.io" - }, - "marketcap_usd": 0, - "name": "Sensitrust Token", - "network": "eth", - "shortcut": "SETS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SEV": { - "address": "0xaf50F8bEc1DbEC013B7025dB444Da019c2f5d488", - "links": { - "Github": "https://github.com/SeveraDAO/Sev-Token", - "Homepage": "https://severadao.ai" - }, - "marketcap_usd": 0, - "name": "SeveraDAO", - "network": "eth", - "shortcut": "SEV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SEXY": { - "address": "0x98F5e9b7F0e33956C0443E81bF7deB8B5b1ed545", - "links": { - "Homepage": "http://sexytoken.co" - }, - "marketcap_usd": 0, - "name": "Sexy Token", - "network": "eth", - "shortcut": "SEXY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SGA": { - "address": "0xed0849BF46CfB9845a2d900A0A4E593F2dD3673c", - "links": { - "Github": "https://github.com/SagaCurrency/smart-contracts", - "Homepage": "https://www.saga.org" - }, - "marketcap_usd": 0, - "name": "SGA Token", - "network": "eth", - "shortcut": "SGA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SGEL": { - "address": "0xa1ccc166faf0E998b3E33225A1A0301B1C86119D", - "links": { - "Homepage": "https://www.soerengelder.com" - }, - "marketcap_usd": 0, - "name": "SGELDER", - "network": "eth", - "shortcut": "SGEL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SGN": { - "address": "0xB2135AB9695a7678Dd590B1A996CB0f37BCB0718", - "links": { - "Homepage": "https://signals.network" - }, - "marketcap_usd": 0, - "name": "Signals Network", - "network": "eth", - "shortcut": "SGN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SGR": { - "address": "0xCB5A05beF3257613E984C17DbcF039952B6d883F", - "links": { - "Homepage": "http://sugarexchange.io" - }, - "marketcap_usd": 0, - "name": "Sugar Exchange", - "network": "eth", - "shortcut": "SGR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SHIB": { - "address": "0x95aD61b0a150d79219dCF64E1E6Cc01f0B64C4cE", - "links": { - "Homepage": "https://shibatoken.com" - }, - "marketcap_usd": 6796478899, - "name": "SHIBA INU", - "network": "eth", - "shortcut": "SHIB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SHIP": { - "address": "0xe25b0BBA01Dc5630312B6A21927E578061A13f55", - "links": { - "Homepage": "https://www.shipchain.io" - }, - "marketcap_usd": 0, - "name": "ShipChain", - "network": "eth", - "shortcut": "SHIP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SHIT": { - "address": "0xEF2E9966eb61BB494E5375d5Df8d67B7dB8A780D", - "links": { - "Homepage": "https://www.shitcoin.io" - }, - "marketcap_usd": 0, - "name": "SHIT", - "network": "eth", - "shortcut": "SHIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SHP": { - "address": "0xEF2463099360a085f1f10b076Ed72Ef625497a06", - "links": { - "Homepage": "https://sharpe.capital" - }, - "marketcap_usd": 0, - "name": "Sharpe Platform Token", - "network": "eth", - "shortcut": "SHP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SIBU": { - "address": "0x980E45AB37c6bcAF93Fe911b3e207e08a3a60B5E", - "links": { - "Github": "https://github.com/SibuToken/sibutoken", - "Homepage": "https://sibutoken.com" - }, - "marketcap_usd": 0, - "name": "SIBU", - "network": "eth", - "shortcut": "SIBU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SIFT": { - "address": "0x8a187D5285d316bcBC9ADafc08b51d70a0d8e000", - "links": { - "Homepage": "https://smartift.com" - }, - "marketcap_usd": 0, - "name": "SIFT", - "network": "eth", - "shortcut": "SIFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SIG": { - "address": "0x6888a16eA9792c15A4DCF2f6C623D055c8eDe792", - "links": { - "Github": "https://github.com/SpectivOfficial", - "Homepage": "https://spectivvr.com" - }, - "marketcap_usd": 0, - "name": "Signal", - "network": "eth", - "shortcut": "SIG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SIH": { - "address": "0x6D728fF862Bfe74be2aba30537E992A24F259a22", - "links": { - "Github": "https://github.com/ClintonK227/SIH-Token", - "Homepage": "https://salientinvestmentholding.com" - }, - "marketcap_usd": 0, - "name": "Salient Investment Holding", - "network": "eth", - "shortcut": "SIH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SION": { - "address": "0xE8d1eFD0c95011298E9A30143A0182c06b45ff5D", - "links": { - "Homepage": "https://sioncrypto.com" - }, - "marketcap_usd": 0, - "name": "SION", - "network": "eth", - "shortcut": "SION", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKB": { - "address": "0x4aF328C52921706dCB739F25786210499169AFe6", - "links": { - "Homepage": "https://www.skb-coin.jp/en" - }, - "marketcap_usd": 364958, - "name": "Sakura Bloom", - "network": "eth", - "shortcut": "SKB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKE": { - "address": "0x13DB74B3cf512F65C4b91683940B4f3955E05085", - "links": { - "Homepage": "http://superkeep.pro/" - }, - "marketcap_usd": 0, - "name": "Super Keep Token", - "network": "eth", - "shortcut": "SKE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKIN": { - "address": "0x2bDC0D42996017fCe214b21607a515DA41A9E0C5", - "links": { - "Github": "https://github.com/Steamtradenet/smart-contract", - "Homepage": "https://skincoin.org" - }, - "marketcap_usd": 53089, - "name": "SKIN", - "network": "eth", - "shortcut": "SKIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKO1": { - "address": "0x4994e81897a920c0FEA235eb8CEdEEd3c6fFF697", - "links": { - "Homepage": "http://www.sikoba.com" - }, - "marketcap_usd": 0, - "name": "Sikoba", - "network": "eth", - "shortcut": "SKO1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKR": { - "address": "0x4c382F8E09615AC86E08CE58266CC227e7d4D913", - "links": { - "Homepage": "https://tokensale.skrilla.com" - }, - "marketcap_usd": 0, - "name": "SKR Token", - "network": "eth", - "shortcut": "SKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKRT": { - "address": "0x887168120cb89Fb06F3E74Dc4AF20D67dF0977f6", - "links": { - "Homepage": "https://www.sekuritance.com" - }, - "marketcap_usd": 0, - "name": "Sekuritance", - "network": "eth", - "shortcut": "SKRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SKYM": { - "address": "0x7297862B9670fF015192799cc849726c88bf1d77", - "links": { - "Github": "https://github.com/SoarEarth", - "Homepage": "https://soar.earth" - }, - "marketcap_usd": 0, - "name": "Skymap Token", - "network": "eth", - "shortcut": "SKYM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SLP": { - "address": "0xCC8Fa225D80b9c7D42F96e9570156c65D6cAAa25", - "links": { - "Homepage": "https://youengine.io" - }, - "marketcap_usd": 137126516, - "name": "Smooth Love Potion", - "network": "eth", - "shortcut": "SLP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SLT": { - "address": "0x7A5fF295Dc8239d5C2374E4D894202aAF029Cab6", - "links": { - "Homepage": "http://smartlands.io" - }, - "marketcap_usd": 0, - "name": "Smartlands", - "network": "eth", - "shortcut": "SLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SLY": { - "address": "0x7928c8aBF1F74eF9F96D4D0a44e3b4209d360785", - "links": { - "Github": "https://github.com/SELFLLERY", - "Homepage": "https://selfllery.com/" - }, - "marketcap_usd": 0, - "name": "Selfllery", - "network": "eth", - "shortcut": "SLY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SMS": { - "address": "0x39013F961c378f02C2b82A6E1d31E9812786FD9D", - "links": { - "Homepage": "https://smscoin.jp/en" - }, - "marketcap_usd": 0, - "name": "Speed Mining Service", - "network": "eth", - "shortcut": "SMS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNC": { - "address": "0xF4134146AF2d511Dd5EA8cDB1C4AC88C57D60404", - "links": { - "Homepage": "https://suncontract.org" - }, - "marketcap_usd": 3613310, - "name": "SunContract", - "network": "eth", - "shortcut": "SNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SND": { - "address": "0xf333b2Ace992ac2bBD8798bF57Bc65a06184afBa", - "links": { - "Homepage": "https://www.sandcoin.io" - }, - "marketcap_usd": 0, - "name": "Sandcoin", - "network": "eth", - "shortcut": "SND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNG": { - "address": "0xcFD6Ae8BF13f42DE14867351eAff7A8A3b9FbBe7", - "links": { - "Github": "https://github.com/SinergiaBlockchain", - "Homepage": "https://sinergiablockchain.org/index-en.html" - }, - "marketcap_usd": 0, - "name": "SINERGIA", - "network": "eth", - "shortcut": "SNG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNGLS": { - "address": "0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009", - "links": { - "Homepage": "https://singulardtv.com" - }, - "marketcap_usd": 0, - "name": "SingularDTV", - "network": "eth", - "shortcut": "SNGLS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNIP": { - "address": "0x44F588aEeB8C44471439D1270B3603c66a9262F1", - "links": { - "Homepage": "https://www.snip.network" - }, - "marketcap_usd": 0, - "name": "SNIP", - "network": "eth", - "shortcut": "SNIP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNM": { - "address": "0x983F6d60db79ea8cA4eB9968C6aFf8cfA04B3c63", - "links": { - "Github": "https://github.com/sonm-io", - "Homepage": "https://sonm.com" - }, - "marketcap_usd": 0, - "name": "SONM", - "network": "eth", - "shortcut": "SNM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNOV": { - "address": "0xBDC5bAC39Dbe132B1E030e898aE3830017D7d969", - "links": { - "Homepage": "https://snovian.space" - }, - "marketcap_usd": 0, - "name": "Snovian.Space", - "network": "eth", - "shortcut": "SNOV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SNT": { - "address": "0x744d70FDBE2Ba4CF95131626614a1763DF805B9E", - "links": { - "Github": "https://github.com/status-im", - "Homepage": "https://status.im" - }, - "marketcap_usd": 117873087, - "name": "Status Network Token", - "network": "eth", - "shortcut": "SNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SOAR": { - "address": "0xD65960FAcb8E4a2dFcb2C2212cb2e44a02e2a57E", - "links": { - "Homepage": "http://soarlabs.org" - }, - "marketcap_usd": 0, - "name": "Soarcoin", - "network": "eth", - "shortcut": "SOAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SOC": { - "address": "0x2d0E95bd4795D7aCe0da3C0Ff7b706a5970eb9D3", - "links": { - "Homepage": "https://www.allsportschain.com" - }, - "marketcap_usd": 2272034, - "name": "All Sports", - "network": "eth", - "shortcut": "SOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SOL": { - "address": "0x1F54638b7737193FFd86c19Ec51907A7c41755D8", - "links": { - "Homepage": "https://sola.foundation" - }, - "marketcap_usd": 0, - "name": "Sola Token", - "network": "eth", - "shortcut": "SOLA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SONIQ": { - "address": "0x1C62aCa2b7605Db3606eAcdA7Bc67A1857DDb8FF", - "links": { - "Homepage": "https://soniqproject.com" - }, - "marketcap_usd": 0, - "name": "Soniq", - "network": "eth", - "shortcut": "SONIQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SOUL": { - "address": "0xBb1f24C0c1554b9990222f036b0AaD6Ee4CAec29", - "links": { - "Github": "https://github.com/cryptosoulgame", - "Homepage": "https://cryptosoul.io/" - }, - "marketcap_usd": 125890, - "name": "CryptoSoul", - "network": "eth", - "shortcut": "SOUL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPACE": { - "address": "0xcc7ab8d78dBA187dC95bF3bB86e65E0C26d0041f", - "links": { - "Github": "https://github.com/thespacelens", - "Homepage": "https://spacetoken.spacelens.com/" - }, - "marketcap_usd": 0, - "name": "Spacelens", - "network": "eth", - "shortcut": "SPACE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPANK": { - "address": "0x42d6622deCe394b54999Fbd73D108123806f6a18", - "links": { - "Homepage": "https://spankchain.com" - }, - "marketcap_usd": 0, - "name": "SpankChain", - "network": "eth", - "shortcut": "SPANK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPARC": { - "address": "0x58bf7df57d9DA7113c4cCb49d8463D4908C735cb", - "links": { - "Homepage": "https://kingsds.network" - }, - "marketcap_usd": 0, - "name": "SPARC", - "network": "eth", - "shortcut": "SPARC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPARTA": { - "address": "0x24AEF3BF1A47561500f9430D74Ed4097C47F51F2", - "links": { - "Homepage": "https://www.spartaico.com" - }, - "marketcap_usd": 0, - "name": "SPARTA", - "network": "eth", - "shortcut": "SPARTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPAZ": { - "address": "0x8F9bfe5b6A5C3fEa8c64ad41a5Cf6f60Ec4aa47c", - "links": { - "Github": "https://github.com/SPZ-TOKEN", - "Homepage": "https://swapcoinz.org" - }, - "marketcap_usd": 0, - "name": "SWAPCOINZ", - "network": "eth", - "shortcut": "SPAZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPC": { - "address": "0x8069080a922834460C3A092FB2c1510224dc066b", - "links": { - "Github": "https://github.com/spacechain/token", - "Homepage": "https://spacechain.com/" - }, - "marketcap_usd": 0, - "name": "SpaceChain", - "network": "eth", - "shortcut": "SPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPD": { - "address": "0x1dEa979ae76f26071870F824088dA78979eb91C8", - "links": { - "Homepage": "https://spindle.zone" - }, - "marketcap_usd": 23855, - "name": "SPINDLE", - "network": "eth", - "shortcut": "SPD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPF": { - "address": "0x85089389C14Bd9c77FC2b8F0c3d1dC3363Bf06Ef", - "links": { - "Homepage": "https://sportyfi.io" - }, - "marketcap_usd": 0, - "name": "Sportify", - "network": "eth", - "shortcut": "SPF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPIRIT": { - "address": "0x92d7A89405Ea3cC605A467E834236e09DF60bf16", - "links": { - "Github": "https://github.com/miitspirit", - "Homepage": "https://spirittoken.net" - }, - "marketcap_usd": 0, - "name": "Spirit", - "network": "eth", - "shortcut": "SPIRIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPN": { - "address": "0x20F7A3DdF244dc9299975b4Da1C39F8D5D75f05A", - "links": { - "Homepage": "https://www.sapien.network/" - }, - "marketcap_usd": 0, - "name": "Sapien", - "network": "eth", - "shortcut": "SPN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SPX": { - "address": "0x05aAaA829Afa407D83315cDED1d45EB16025910c", - "links": { - "Homepage": "https://sp8de.com" - }, - "marketcap_usd": 0, - "name": "Sp8de", - "network": "eth", - "shortcut": "SPX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SRN": { - "address": "0x68d57c9a1C35f63E2c83eE8e49A64e9d70528D25", - "links": { - "Github": "https://github.com/sirin-labs/crowdsale-smart-contract", - "Homepage": "https://sirinlabs.com" - }, - "marketcap_usd": 916240, - "name": "Sirin Labs", - "network": "eth", - "shortcut": "SRN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SRX": { - "address": "0x32F3b8A00B6912D0314be212fe9538B7B9430c12", - "links": { - "Github": "https://github.com/SiriusX-Token", - "Homepage": "https://siriusxtravel.com" - }, - "marketcap_usd": 0, - "name": "SiriusX", - "network": "eth", - "shortcut": "SRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SSP": { - "address": "0x624d520BAB2E4aD83935Fa503fB130614374E850", - "links": { - "Homepage": "https://smartshare.vip/#" - }, - "marketcap_usd": 150024, - "name": "Smartshare", - "network": "eth", - "shortcut": "SSP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STABIT": { - "address": "0x4A89cD486fA996ad50c0a63C35c78702f5422a50", - "links": { - "Homepage": "https://stabitcoin.com/" - }, - "marketcap_usd": 0, - "name": "StabitCoin", - "network": "eth", - "shortcut": "STABIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STAC": { - "address": "0x9a005c9a89BD72a4Bd27721E7a09A3c11D2b03C4", - "links": { - "Homepage": "https://coinstarter.com" - }, - "marketcap_usd": 9313, - "name": "Starter Coin", - "network": "eth", - "shortcut": "STAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STACS": { - "address": "0x286708f069225905194673755F12359e6afF6FE1", - "links": { - "Homepage": "https://stacs.io" - }, - "marketcap_usd": 0, - "name": "STACS", - "network": "eth", - "shortcut": "STACS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STAR": { - "address": "0xF70a642bD387F94380fFb90451C2c81d4Eb82CBc", - "links": { - "Homepage": "http://starbase.co" - }, - "marketcap_usd": 37318, - "name": "Star Token", - "network": "eth", - "shortcut": "STAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STATE": { - "address": "0x00C2999c8B2AdF4ABC835cc63209533973718eB1", - "links": { - "Github": "https://github.com/aave", - "Homepage": "https://nwo.capital " - }, - "marketcap_usd": 0, - "name": "New World Order", - "network": "eth", - "shortcut": "STATE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STB": { - "address": "0x09BcA6eBAb05Ee2ae945BE4edA51393d94Bf7b99", - "links": { - "Github": "https://github.com/stableproject/", - "Homepage": "https://stable.foundation" - }, - "marketcap_usd": 0, - "name": "STABLE Token", - "network": "eth", - "shortcut": "STB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STC": { - "address": "0x629aEe55ed49581C33ab27f9403F7992A289ffd5", - "links": { - "Github": "https://github.com/DimensionsNetwork", - "Homepage": "https://dimensions.network" - }, - "marketcap_usd": 0, - "name": "StrikeCoin Token", - "network": "eth", - "shortcut": "STC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STK": { - "address": "0xaE73B38d1c9A8b274127ec30160a4927C4d71824", - "links": { - "Homepage": "https://stktoken.com" - }, - "marketcap_usd": 0, - "name": "STK Token", - "network": "eth", - "shortcut": "STK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STL": { - "address": "0xC1Ad68c43508dD5AdDb8d0ac0927dbE752d149D6", - "links": { - "Homepage": "https://stablecoinswap.io/" - }, - "marketcap_usd": 0, - "name": "Stablecoinswap", - "network": "eth", - "shortcut": "STL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STM": { - "address": "0x302ce6674A16b54bA1B8A49FED64C471EdE6C174", - "links": { - "Homepage": "https://seven-trust-mongolia.mn" - }, - "marketcap_usd": 0, - "name": "StmToken", - "network": "eth", - "shortcut": "STM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STN": { - "address": "0x599346779e90fc3F5F997b5ea715349820F91571", - "links": { - "Homepage": "https://saturn.network" - }, - "marketcap_usd": 0, - "name": "Saturn Network", - "network": "eth", - "shortcut": "STN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STORJ": { - "address": "0xB64ef51C888972c908CFacf59B47C1AfBC0Ab8aC", - "links": { - "Github": "https://github.com/Storj", - "Homepage": "https://storj.io" - }, - "marketcap_usd": 178806759, - "name": "STORJ", - "network": "eth", - "shortcut": "STORJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STORM": { - "address": "0xD0a4b8946Cb52f0661273bfbC6fD0E0C75Fc6433", - "links": { - "Homepage": "https://www.stormtoken.com" - }, - "marketcap_usd": 0, - "name": "Storm Token", - "network": "eth", - "shortcut": "STORM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STP": { - "address": "0xecd570bBf74761b960Fa04Cc10fe2c4e86FfDA36", - "links": { - "Github": "https://github.com/stashpayio", - "Homepage": "https://stashpay.io" - }, - "marketcap_usd": 0, - "name": "StashPay", - "network": "eth", - "shortcut": "STP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STQ": { - "address": "0x5c3a228510D246b78a3765C20221Cbf3082b44a4", - "links": { - "Github": "https://github.com/Storiqa/", - "Homepage": "https://storiqa.com" - }, - "marketcap_usd": 0, - "name": "Storiqa", - "network": "eth", - "shortcut": "STQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STR": { - "address": "0xBAE235823D7255D9D48635cEd4735227244Cd583", - "links": { - "Homepage": "https://staker.network" - }, - "marketcap_usd": 0, - "name": "Staker", - "network": "eth", - "shortcut": "STR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STRC": { - "address": "0x46492473755e8dF960F8034877F61732D718CE96", - "links": { - "Github": "https://github.com/sprux/BackToEarth", - "Homepage": "https://backto.earth" - }, - "marketcap_usd": 0, - "name": "STRC", - "network": "eth", - "shortcut": "STRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STU": { - "address": "0x0371A82e4A9d0A4312f3ee2Ac9c6958512891372", - "links": { - "Homepage": "https://bitjob.io" - }, - "marketcap_usd": 0, - "name": "bitJob", - "network": "eth", - "shortcut": "STU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:STX": { - "address": "0x006BeA43Baa3f7A6f765F14f10A1a1b08334EF45", - "links": { - "Github": "https://github.com/stx-technologies/stox-token", - "Homepage": "https://www.stox.com" - }, - "marketcap_usd": 184023, - "name": "StoxToken", - "network": "eth", - "shortcut": "STX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SUB": { - "address": "0x8D75959f1E61EC2571aa72798237101F084DE63a", - "links": { - "Github": "https://github.com/SubstratumNetwork", - "Homepage": "https://substratum.net" - }, - "marketcap_usd": 186040, - "name": "Substratum", - "network": "eth", - "shortcut": "SUB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SUR": { - "address": "0xe120c1ECBfdFeA7F0A8f0Ee30063491E8c26fedf", - "links": { - "Homepage": "https://www.suretly.com" - }, - "marketcap_usd": 0, - "name": "Suretly", - "network": "eth", - "shortcut": "SUR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SUSHI": { - "address": "0x6B3595068778DD592e39A122f4f5a5cF09C90fE2", - "links": { - "Github": "https://github.com/sushiswap", - "Homepage": "https://sushiswapclassic.org/" - }, - "marketcap_usd": 288234769, - "name": "SushiToken", - "network": "eth", - "shortcut": "SUSHI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SVD": { - "address": "0xbdEB4b83251Fb146687fa19D1C660F99411eefe3", - "links": { - "Homepage": "https://ico.savedroid.com" - }, - "marketcap_usd": 0, - "name": "savedroid", - "network": "eth", - "shortcut": "SVD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWAP": { - "address": "0xC958e9FB59724f8b0927426a8836F1158F0d03cf", - "links": { - "Github": "https://github.com/swaps-network", - "Homepage": "https://swaps.network/" - }, - "marketcap_usd": 0, - "name": "SWAPS.NETWORK", - "network": "eth", - "shortcut": "SWAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWASH": { - "address": "0xA130E3a33a4d84b04c3918c4E5762223Ae252F80", - "links": { - "Github": "https://github.com/swashapp/", - "Homepage": "https://swashapp.io/" - }, - "marketcap_usd": 12397242, - "name": "Swash Token", - "network": "eth", - "shortcut": "SWASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWFTC": { - "address": "0x0bb217E40F8a5Cb79Adf04E1aAb60E5abd0dfC1e", - "links": { - "Homepage": "http://www.swftcoin.com" - }, - "marketcap_usd": 5259537, - "name": "SwftCoin", - "network": "eth", - "shortcut": "SWFTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWM": { - "address": "0x9e88613418cF03dCa54D6a2cf6Ad934A78C7A17A", - "links": { - "Github": "https://github.com/swarmfund", - "Homepage": "https://swarm.fund" - }, - "marketcap_usd": 0, - "name": "Swarm Fund Token", - "network": "eth", - "shortcut": "SWM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWRM": { - "address": "0x6e2050CBFB3eD8A4d39b64cC9f47E711a03a5a89", - "links": { - "Homepage": "https://www.stream.space" - }, - "marketcap_usd": 0, - "name": "StreamShares", - "network": "eth", - "shortcut": "SWRM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SWT": { - "address": "0xB9e7F8568e08d5659f5D29C4997173d84CdF2607", - "links": { - "Homepage": "http://swarm.city" - }, - "marketcap_usd": 264688, - "name": "Swarm City Token", - "network": "eth", - "shortcut": "SWT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SXDT": { - "address": "0x12B306fA98F4CbB8d4457FdFf3a0A0a56f07cCdf", - "links": { - "Homepage": "http://www.spectre.ai" - }, - "marketcap_usd": 0, - "name": "Spectre.ai D-Token", - "network": "eth", - "shortcut": "SXDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SXR": { - "address": "0xfCdaE8771F8d28E3B9027AB58F4A20749767a097", - "links": { - "Github": "https://github.com/XAInteractive", - "Homepage": "https://www.xainteractive.com" - }, - "marketcap_usd": 0, - "name": "SecureXR", - "network": "eth", - "shortcut": "SXR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SXUT": { - "address": "0x2C82c73d5B34AA015989462b2948cd616a37641F", - "links": { - "Homepage": "http://www.spectre.ai" - }, - "marketcap_usd": 0, - "name": "Spectre.ai U-Token", - "network": "eth", - "shortcut": "SXUT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SYN": { - "address": "0x10B123FdDde003243199aaD03522065dC05827A0", - "links": { - "Homepage": "https://synapse.ai" - }, - "marketcap_usd": 0, - "name": "Synapse", - "network": "eth", - "shortcut": "SYN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SYS": { - "address": "0x46EaF75e6d391708b7F1a0D56875D90844119521", - "links": { - "Homepage": "https://syscoin.org" - }, - "marketcap_usd": 0, - "name": "Syscoin", - "network": "eth", - "shortcut": "SYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SYSX": { - "address": "0x3A0D746B3EA1d8ccDf19aD915913BD68391133Ca", - "links": { - "Github": "https://github.com/syscoin", - "Homepage": "https://syscoin.org" - }, - "marketcap_usd": 0, - "name": "SyscoinToken", - "network": "eth", - "shortcut": "SYSX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:SenSatorI": { - "address": "0x4cA74185532DC1789527194e5B9c866dD33F4E82", - "links": { - "Homepage": "http://theglobalbitcoin.com" - }, - "marketcap_usd": 0, - "name": "SenSatorI Token", - "network": "eth", - "shortcut": "SenSatorI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:Skey": { - "address": "0x06A01a4d579479Dd5D884EBf61A31727A3d8D442", - "links": { - "Github": "https://github.com/skey-network", - "Homepage": "https://skey.network" - }, - "marketcap_usd": 3338194, - "name": "Skey Network", - "network": "eth", - "shortcut": "Skey", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TALAO": { - "address": "0x1D4cCC31dAB6EA20f461d329a0562C1c58412515", - "links": { - "Homepage": "https://www.talao.io" - }, - "marketcap_usd": 0, - "name": "Talao", - "network": "eth", - "shortcut": "TALAO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TAN": { - "address": "0x2C36204a0712A2a50E54A62F7c4F01867e78cB53", - "links": { - "Homepage": "https://taklimakan.io" - }, - "marketcap_usd": 0, - "name": "Taklimakan Network", - "network": "eth", - "shortcut": "TAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TAU": { - "address": "0xc27A2F05fa577a83BA0fDb4c38443c0718356501", - "links": { - "Github": "https://github.com/lamden", - "Homepage": "https://www.lamden.io" - }, - "marketcap_usd": 0, - "name": "Lamden Tau", - "network": "eth", - "shortcut": "TAU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TAUD": { - "address": "0x00006100F7090010005F1bd7aE6122c3C2CF0090", - "links": { - "Github": "https://github.com/trusttoken", - "Homepage": "https://www.trusttoken.com/trueaud" - }, - "marketcap_usd": 0, - "name": "TrueAUD", - "network": "eth", - "shortcut": "TAUD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TAUR": { - "address": "0x64786063A352b399d44de2875909D1229F120eBE", - "links": { - "Homepage": "http://taurcoin.com" - }, - "marketcap_usd": 0, - "name": "TAUR", - "network": "eth", - "shortcut": "TAUR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TBC": { - "address": "0x627974847450C45b60B3Fe3598f4e6E4cf945B9a", - "links": { - "Github": "https://github.com/THUNDERBOLTCOIN", - "Homepage": "http://thunderboltcoin.es" - }, - "marketcap_usd": 0, - "name": "ThunderBoltCoin", - "network": "eth", - "shortcut": "TBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TBC2": { - "address": "0xFACCD5Fc83c3E4C3c1AC1EF35D15adf06bCF209C", - "links": { - "Github": "https://github.com/erc20club", - "Homepage": "https://www.tbc.erc20.club" - }, - "marketcap_usd": 0, - "name": "TBC2", - "network": "eth", - "shortcut": "TBC2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TBT": { - "address": "0xAFe60511341a37488de25Bef351952562E31fCc1", - "links": { - "Github": "https://github.com/tbitbot", - "Homepage": "https://tbitbot.com" - }, - "marketcap_usd": 0, - "name": "TBitBot", - "network": "eth", - "shortcut": "TBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TBTC": { - "address": "0x8dAEBADE922dF735c38C80C7eBD708Af50815fAa", - "links": { - "Github": "https://github.com/keep-network", - "Homepage": "https://tbtc.network" - }, - "marketcap_usd": 0, - "name": "TBTC", - "network": "eth", - "shortcut": "TBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TBX": { - "address": "0x3A92bD396aEf82af98EbC0Aa9030D25a23B11C6b", - "links": { - "Homepage": "https://tokenbox.io" - }, - "marketcap_usd": 14975, - "name": "Tokenbox", - "network": "eth", - "shortcut": "TBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCA": { - "address": "0xfA0eF5E034CaE1AE752d59bdb8aDcDe37Ed7aB97", - "links": { - "Github": "https://github.com/TcandyChain", - "Homepage": "https://www.tcandy.io" - }, - "marketcap_usd": 0, - "name": "TangguoTao Token", - "network": "eth", - "shortcut": "TCA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCAD": { - "address": "0x00000100F2A2bd000715001920eB70D229700085", - "links": { - "Github": "https://github.com/trusttoken", - "Homepage": "https://www.trusttoken.com/truecad" - }, - "marketcap_usd": 0, - "name": "TrueCAD", - "network": "eth", - "shortcut": "TCAD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCH": { - "address": "0x9972A0F24194447E73a7e8b6CD26a52e02DDfAD5", - "links": { - "Homepage": "https://www.thorecash.com" - }, - "marketcap_usd": 5891, - "name": "Thore Cash", - "network": "eth", - "shortcut": "TCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCNX": { - "address": "0x28d7F432d24ba6020d1cbD4f28BEDc5a82F24320", - "links": { - "Homepage": "https://www.tercet.network" - }, - "marketcap_usd": 0, - "name": "Tercet Network", - "network": "eth", - "shortcut": "TCNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCST": { - "address": "0x9910f4AeD4A7550A4120ad7da8dF8b56E91197Fa", - "links": { - "Homepage": "https://sto.tradecloud.sg/#token-metrics-section" - }, - "marketcap_usd": 0, - "name": "TradeCloud Security Token", - "network": "eth", - "shortcut": "TCST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TCT": { - "address": "0xED82730312babb41367E060911F798002FFA445F", - "links": { - "Github": "https://github.com/TheCryptoTech", - "Homepage": "https://coin.thecryptotech.net" - }, - "marketcap_usd": 0, - "name": "The Crypto Tech", - "network": "eth", - "shortcut": "TCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TDH": { - "address": "0x2a1dbabe65c595B0022e75208C34014139d5d357", - "links": { - "Homepage": "https://trustedhealth.io" - }, - "marketcap_usd": 0, - "name": "TrustedHealth", - "network": "eth", - "shortcut": "TDH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TDX": { - "address": "0x317eb4ad9cfaC6232f0046831322E895507bcBeb", - "links": { - "Homepage": "https://tidex.com/" - }, - "marketcap_usd": 0, - "name": "Tidex Token", - "network": "eth", - "shortcut": "TDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TEAM": { - "address": "0x1c79ab32C66aCAa1e9E81952B8AAa581B43e54E7", - "links": { - "Homepage": "https://tokenstars.com/team" - }, - "marketcap_usd": 0, - "name": "TEAM (TokenStars)", - "network": "eth", - "shortcut": "TEAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TECH": { - "address": "0xA1BA7186eeC1Be5114b0Cf49b95B23aDC4131B51", - "links": { - "Homepage": "https://futuretechinsider.com" - }, - "marketcap_usd": 0, - "name": "FTI NEWS Token", - "network": "eth", - "shortcut": "TECH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TEN": { - "address": "0xDD16eC0F66E54d453e6756713E533355989040E4", - "links": { - "Homepage": "https://www.tokenomy.com" - }, - "marketcap_usd": 5058206, - "name": "Tokenomy", - "network": "eth", - "shortcut": "TEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TENX": { - "address": "0x515bA0a2E286AF10115284F151cF398688A69170", - "links": { - "Github": "https://github.com/tenx-tech/tenx-token", - "Homepage": "https://tenx.tech/en/" - }, - "marketcap_usd": 0, - "name": "TENX", - "network": "eth", - "shortcut": "TENX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TFD": { - "address": "0xE5F166c0D8872B68790061317BB6CcA04582C912", - "links": { - "Homepage": "https://ico.tefoodint.com" - }, - "marketcap_usd": 0, - "name": "TE-FOOD", - "network": "eth", - "shortcut": "TFD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TFL": { - "address": "0xa7f976C360ebBeD4465c2855684D1AAE5271eFa9", - "links": { - "Github": "https://github.com/TrueFlip", - "Homepage": "https://trueflip.io" - }, - "marketcap_usd": 0, - "name": "TrueFlip", - "network": "eth", - "shortcut": "TFL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TGAME": { - "address": "0xF8e06E4e4A80287FDCa5b02dcCecAa9D0954840F", - "links": { - "Homepage": "https://ico.truegame.io" - }, - "marketcap_usd": 0, - "name": "Truegame", - "network": "eth", - "shortcut": "TGAME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TGBP": { - "address": "0x00000000441378008EA67F4284A57932B1c000a5", - "links": { - "Github": "https://github.com/trusttoken", - "Homepage": "https://www.trusttoken.com/truegbp" - }, - "marketcap_usd": 0, - "name": "TrueGBP", - "network": "eth", - "shortcut": "TGBP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:THKD": { - "address": "0x0000852600CEB001E08e00bC008be620d60031F2", - "links": { - "Github": "https://github.com/trusttoken", - "Homepage": "https://www.trusttoken.com/truehkd" - }, - "marketcap_usd": 0, - "name": "TrueHKD", - "network": "eth", - "shortcut": "THKD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:THR": { - "address": "0x1Cb3209D45B2a60B7fBCA1cCDBF87f674237A4aa", - "links": { - "Homepage": "https://www.thorecoin.com" - }, - "marketcap_usd": 0, - "name": "ThoreCoin", - "network": "eth", - "shortcut": "THR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:THRT": { - "address": "0x4f27053F32edA8Af84956437Bc00e5fFa7003287", - "links": { - "Homepage": "https://ico.thrivelabs.io" - }, - "marketcap_usd": 0, - "name": "Thrive Token", - "network": "eth", - "shortcut": "THRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:THUG": { - "address": "0xfe7B915A0bAA0E79f85c5553266513F7C1c03Ed0", - "links": { - "Github": "https://github.com/THUGCOIN/THUGCoin", - "Homepage": "https://thugcoin.cash" - }, - "marketcap_usd": 0, - "name": "THUG", - "network": "eth", - "shortcut": "THUG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIE": { - "address": "0x999967E2Ec8A74B7c8E9dB19E039d920B31d39D0", - "links": { - "Homepage": "https://ties.network" - }, - "marketcap_usd": 0, - "name": "Ties.DB", - "network": "eth", - "shortcut": "TIE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIG": { - "address": "0xEee2d00Eb7DEB8Dd6924187f5AA3496B7d06E62A", - "links": { - "Homepage": "https://www.tigereum.io" - }, - "marketcap_usd": 0, - "name": "Tigereum", - "network": "eth", - "shortcut": "TIG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIK": { - "address": "0x0922F1D808aDc3A4444BEd2F73fAC53a1A2A5859", - "links": { - "Homepage": "https://chronobase.eu/" - }, - "marketcap_usd": 145674, - "name": "ChronoBase", - "network": "eth", - "shortcut": "TIK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIME": { - "address": "0x6531f133e6DeeBe7F2dcE5A0441aA7ef330B4e53", - "links": { - "Homepage": "https://chronobank.io" - }, - "marketcap_usd": 0, - "name": "Chronobank", - "network": "eth", - "shortcut": "TIME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIO": { - "address": "0x80BC5512561c7f85A3A9508c7df7901b370Fa1DF", - "links": { - "Homepage": "https://trade.io" - }, - "marketcap_usd": 0, - "name": "TIO", - "network": "eth", - "shortcut": "TIO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TIX": { - "address": "0xEa1f346faF023F974Eb5adaf088BbCdf02d761F4", - "links": { - "Homepage": "https://www.blocktix.io" - }, - "marketcap_usd": 0, - "name": "Blocktix", - "network": "eth", - "shortcut": "TIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TKA": { - "address": "0xdaE1Baf249964bc4b6aC98c3122f0e3E785fd279", - "links": { - "Homepage": "https://www.tokia.io" - }, - "marketcap_usd": 0, - "name": "Tokia", - "network": "eth", - "shortcut": "TKA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TKLN": { - "address": "0x0675DAa94725A528b05A3A88635C03EA964BFA7E", - "links": { - "Homepage": "https://taklimakan.io" - }, - "marketcap_usd": 0, - "name": "Taklimakan Network", - "network": "eth", - "shortcut": "TKLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TKN": { - "address": "0xaAAf91D9b90dF800Df4F55c205fd6989c977E73a", - "links": { - "Homepage": "https://etherscan.io/token/TokenCard" - }, - "marketcap_usd": 2583432, - "name": "TokenCard", - "network": "eth", - "shortcut": "TKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TKP": { - "address": "0xd31695a1d35E489252CE57b129FD4b1B05E6AcaC", - "links": { - "Github": "https://github.com/Tokpie/tokpie-contract", - "Homepage": "https://tokpie.io/" - }, - "marketcap_usd": 4434791, - "name": "TOKPIE", - "network": "eth", - "shortcut": "TKP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TLN": { - "address": "0x679131F591B4f369acB8cd8c51E68596806c3916", - "links": { - "Github": "https://github.com/trustlines-protocol", - "Homepage": "https://trustlines.network/" - }, - "marketcap_usd": 0, - "name": "Trustlines Network Token", - "network": "eth", - "shortcut": "TLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TLX": { - "address": "0xb3616550aBc8AF79c7A5902DEF9Efa3bC9A95200", - "links": { - "Homepage": "https://telexai.com" - }, - "marketcap_usd": 0, - "name": "Telex", - "network": "eth", - "shortcut": "TLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TMT": { - "address": "0x3209f98BeBF0149B769ce26D71F7aEA8E435EfEa", - "links": { - "Homepage": "http://traxia.co" - }, - "marketcap_usd": 0, - "name": "TRAXIA", - "network": "eth", - "shortcut": "TMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TNO": { - "address": "0xAD6683b7f3618c44F5CA6040902812Dd890DdE4d", - "links": { - "Github": "https://github.com/TNOSCOINS/TNOS", - "Homepage": "https://tnoscoin.cash" - }, - "marketcap_usd": 0, - "name": "TNOS COIN", - "network": "eth", - "shortcut": "TNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TNS": { - "address": "0xb0280743b44bF7db4B6bE482b2Ba7b75E5dA096C", - "links": { - "Homepage": "https://transcodium.com" - }, - "marketcap_usd": 28525, - "name": "Transcodium", - "network": "eth", - "shortcut": "TNS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TNT": { - "address": "0x08f5a9235B08173b7569F83645d2c7fB55e8cCD8", - "links": { - "Github": "https://github.com/tierion", - "Homepage": "https://tierion.com" - }, - "marketcap_usd": 0, - "name": "Tierion Network Token", - "network": "eth", - "shortcut": "TNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TOK": { - "address": "0x9a49f02e128a8E989b443a8f94843C0918BF45E7", - "links": { - "Homepage": "https://www.tokok.com/" - }, - "marketcap_usd": 0, - "name": "TOKOK", - "network": "eth", - "shortcut": "TOK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TOOR": { - "address": "0x8eb965ee9cCFBCE76c0a06264492c0afEfc2826d", - "links": { - "Github": "https://github.com/toorister/toorcoin", - "Homepage": "https://www.toorcoin.com" - }, - "marketcap_usd": 0, - "name": "ToorCoin", - "network": "eth", - "shortcut": "TOOR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRAC": { - "address": "0xaA7a9CA87d3694B5755f213B5D04094b8d0F0A6F", - "links": { - "Homepage": "https://origintrail.io" - }, - "marketcap_usd": 134439035, - "name": "OriginTrail", - "network": "eth", - "shortcut": "TRAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRAK": { - "address": "0x12759512D326303B45f1ceC8F7B6fd96F387778E", - "links": { - "Homepage": "http://www.trakinvest.com" - }, - "marketcap_usd": 0, - "name": "TrakInvest", - "network": "eth", - "shortcut": "TRAK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRCN": { - "address": "0x566Fd7999B1Fc3988022bD38507A48F0bCf22c77", - "links": { - "Homepage": "http://www.therealcoinz.com" - }, - "marketcap_usd": 0, - "name": "The Real Coin", - "network": "eth", - "shortcut": "TRCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRCT": { - "address": "0x30ceCB5461A449A90081F5a5F55db4e048397BAB", - "links": { - "Homepage": "http://www.tracto.org" - }, - "marketcap_usd": 0, - "name": "Tracto", - "network": "eth", - "shortcut": "TRCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRDT": { - "address": "0x33f90Dee07c6E8B9682dD20F73E6C358B2ED0f03", - "links": { - "Homepage": "https://www.tridentgroup.io" - }, - "marketcap_usd": 0, - "name": "Trident Group", - "network": "eth", - "shortcut": "TRDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRST": { - "address": "0xCb94be6f13A1182E4A4B6140cb7bf2025d28e41B", - "links": { - "Github": "https://github.com/WeTrustPlatform", - "Homepage": "https://www.wetrust.io" - }, - "marketcap_usd": 184461, - "name": "WeTrust", - "network": "eth", - "shortcut": "TRST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TRUCCO": { - "address": "0xf10E3E8F6B02B594b7C95fca59DC7E5ce7364df5", - "links": { - "Homepage": "https://trucco.com" - }, - "marketcap_usd": 0, - "name": "Truco Token", - "network": "eth", - "shortcut": "TRUCCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TSW": { - "address": "0x6B87999bE87358065bBdE41e8a0fe0B7b1cd2514", - "links": { - "Homepage": "https://www.teslawatt.com" - }, - "marketcap_usd": 0, - "name": "TeslaWatt", - "network": "eth", - "shortcut": "TSW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TTA": { - "address": "0xaaB606817809841E8b1168be8779Eeaf6744Ef64", - "links": { - "Github": "http://github.com/TendTechnologies", - "Homepage": "https://www.tend.swiss" - }, - "marketcap_usd": 0, - "name": "Tend Token", - "network": "eth", - "shortcut": "TTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TTC": { - "address": "0x9389434852b94bbaD4c8AfEd5B7BDBc5Ff0c2275", - "links": { - "Homepage": "http://www.ttc.eco" - }, - "marketcap_usd": 0, - "name": "TTC Protocol", - "network": "eth", - "shortcut": "TTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TTU": { - "address": "0x9CDa8A60dd5AfA156c95Bd974428d91a0812e054", - "links": { - "Homepage": "https://tatatutoken.io" - }, - "marketcap_usd": 0, - "name": "TaTaTu", - "network": "eth", - "shortcut": "TTU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TTV": { - "address": "0xa838be6E4b760E6061D4732D6B9F11Bf578f9A76", - "links": { - "Github": "https://github.com/tvtwocom", - "Homepage": "https://tv-two.com" - }, - "marketcap_usd": 0, - "name": "TV-TWO: Token for Television", - "network": "eth", - "shortcut": "TTV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TUSD": { - "address": "0x0000000000085d4780B73119b644AE5ecd22b376", - "links": { - "Github": "https://github.com/trusttoken", - "Homepage": "https://www.trusttoken.com" - }, - "marketcap_usd": 1116979619, - "name": "TrueUSD", - "network": "eth", - "shortcut": "TUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TWN": { - "address": "0x2eF1aB8a26187C58BB8aAeB11B2fC6D25C5c0716", - "links": { - "Homepage": "https://ico.theworldnews.net" - }, - "marketcap_usd": 0, - "name": "The World News", - "network": "eth", - "shortcut": "TWN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TWNKL": { - "address": "0xfbd0d1c77B501796A35D86cF91d65D9778EeE695", - "links": { - "Homepage": "https://www.rainbowcurrency.com/" - }, - "marketcap_usd": 0, - "name": "Twinkle", - "network": "eth", - "shortcut": "TWNKL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:TaaS": { - "address": "0xE7775A6e9Bcf904eb39DA2b68c5efb4F9360e08C", - "links": { - "Homepage": "https://taas.fund" - }, - "marketcap_usd": 0, - "name": "Token-as-a-Service", - "network": "eth", - "shortcut": "TaaS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:Thar": { - "address": "0x96c30D5499EF6eA96A9c221Bc18BC39D29c97F27", - "links": { - "Github": "https://github.com/Thartoken", - "Homepage": "https://thartoken.com" - }, - "marketcap_usd": 0, - "name": "Thar token", - "network": "eth", - "shortcut": "Thar", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UBEX": { - "address": "0x6704B673c70dE9bF74C8fBa4b4bd748F0e2190E1", - "links": { - "Github": "https://github.com/ubex-ai", - "Homepage": "https://www.ubex.com/" - }, - "marketcap_usd": 125184, - "name": "UBEX Token", - "network": "eth", - "shortcut": "UBEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UBT": { - "address": "0x8400D94A5cb0fa0D041a3788e395285d61c9ee5e", - "links": { - "Homepage": "https://unibright.io" - }, - "marketcap_usd": 22769484, - "name": "Unibright", - "network": "eth", - "shortcut": "UBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UCASH": { - "address": "0x92e52a1A235d9A103D970901066CE910AAceFD37", - "links": { - "Homepage": "https://u.cash" - }, - "marketcap_usd": 0, - "name": "U.CASH", - "network": "eth", - "shortcut": "UCASH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UCBI": { - "address": "0x2adba23Cf1252dE095aCEd801e758b369EC10426", - "links": { - "Github": "https://github.com/UCBI-Blockchain-Data-Banking/UCBI-Banking", - "Homepage": "https://ucbibanking.com" - }, - "marketcap_usd": 0, - "name": "UCBI Banking", - "network": "eth", - "shortcut": "UCBI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UCN": { - "address": "0xAAf37055188Feee4869dE63464937e683d61b2a1", - "links": { - "Homepage": "https://uchain.world" - }, - "marketcap_usd": 0, - "name": "UChain", - "network": "eth", - "shortcut": "UCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UFR": { - "address": "0xEA097A2b1dB00627B2Fa17460Ad260c016016977", - "links": { - "Homepage": "https://www.upfiring.com" - }, - "marketcap_usd": 415184, - "name": "Upfiring", - "network": "eth", - "shortcut": "UFR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UKG": { - "address": "0x24692791Bc444c5Cd0b81e3CBCaba4b04Acd1F3B", - "links": { - "Github": "https://github.com/unikoingold/UnikoinGold-UKG-Contract", - "Homepage": "https://unikoingold.com" - }, - "marketcap_usd": 0, - "name": "UnikoinGold", - "network": "eth", - "shortcut": "UKG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UMB": { - "address": "0x6fC13EACE26590B80cCCAB1ba5d51890577D83B2", - "links": { - "Github": "https://github.com/umbrella-network", - "Homepage": "https://umb.network/" - }, - "marketcap_usd": 1566544, - "name": "Umbrella", - "network": "eth", - "shortcut": "UMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UNI": { - "address": "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984", - "links": { - "Homepage": "https://uniswap.org/" - }, - "marketcap_usd": 4976163328, - "name": "Uniswap", - "network": "eth", - "shortcut": "UNI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UP": { - "address": "0x6Ba460AB75Cd2c56343b3517ffeBA60748654D26", - "links": { - "Homepage": "https://uptoken.org" - }, - "marketcap_usd": 46974, - "name": "UpToken", - "network": "eth", - "shortcut": "UP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UPP": { - "address": "0xC86D054809623432210c107af2e3F619DcFbf652", - "links": { - "Homepage": "https://sentinelprotocol.io" - }, - "marketcap_usd": 34499041, - "name": "Sentinel Protocol", - "network": "eth", - "shortcut": "UPP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UQC": { - "address": "0xD01DB73E047855Efb414e6202098C4Be4Cd2423B", - "links": { - "Homepage": "https://uquidcoin.com" - }, - "marketcap_usd": 0, - "name": "Uquid Coin", - "network": "eth", - "shortcut": "UQC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:URAC": { - "address": "0xff8Be4B22CeDC440591dcB1E641EB2a0dd9d25A5", - "links": { - "Github": "https://github.com/UranusBlockStack/uranus", - "Homepage": "https://www.uranus.io/" - }, - "marketcap_usd": 0, - "name": "URACToken ", - "network": "eth", - "shortcut": "URAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:URB": { - "address": "0x931684139f756C24eC0731E9F74FE50e5548dDeF", - "links": { - "Github": "https://github.com/urbitdata", - "Homepage": "https://urbitdata.io" - }, - "marketcap_usd": 0, - "name": "Urbit Data", - "network": "eth", - "shortcut": "URB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USD-G": { - "address": "0xfB0aaA0432112779d9AC483D9d5E3961ecE18eec", - "links": { - "Github": "https://github.com/gluwa/Gluwacoin", - "Homepage": "https://www.gluwa.com/gluwacoin" - }, - "marketcap_usd": 0, - "name": "USD Gluwacoin", - "network": "eth", - "shortcut": "USD-G", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USDC": { - "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "links": { - "Github": "https://github.com/centrehq/centre-tokens", - "Homepage": "https://www.centre.io" - }, - "marketcap_usd": 42518789234, - "name": "USD//Coin", - "network": "eth", - "shortcut": "USDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USDP": { - "address": "0x8E870D67F660D95d5be530380D0eC0bd388289E1", - "links": { - "Github": "https://github.com/paxosglobal", - "Homepage": "https://www.paxos.com/standard" - }, - "marketcap_usd": 877457873, - "name": "Paxos Standard (PAX)", - "network": "eth", - "shortcut": "USDP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USDS": { - "address": "0xA4Bdb11dc0a2bEC88d24A3aa1E6Bb17201112eBe", - "links": { - "Homepage": "https://stably.io" - }, - "marketcap_usd": 462366, - "name": "StableUSD", - "network": "eth", - "shortcut": "USDS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USDT": { - "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", - "links": { - "Homepage": "https://tether.to" - }, - "marketcap_usd": 70941600691, - "name": "USD Tether (erc20)", - "network": "eth", - "shortcut": "USDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:USDx": { - "address": "0xeb269732ab75A6fD61Ea60b06fE994cD32a83549", - "links": { - "Github": "https://github.com/dforcenetwork", - "Homepage": "https://dforce.network" - }, - "marketcap_usd": 0, - "name": "dForce Stablecoin", - "network": "eth", - "shortcut": "USDx", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UTK": { - "address": "0xdc9Ac3C20D1ed0B540dF9b1feDC10039Df13F99c", - "links": { - "Github": "https://github.com/utrustdev/", - "Homepage": "https://utrust.com" - }, - "marketcap_usd": 58070830, - "name": "Utrust", - "network": "eth", - "shortcut": "UTK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UTNP": { - "address": "0x9e3319636e2126e3c0bc9e3134AEC5e1508A46c7", - "links": { - "Github": "https://github.com/UniversaBlockchain/universa", - "Homepage": "https://www.universa.io" - }, - "marketcap_usd": 0, - "name": "Universa", - "network": "eth", - "shortcut": "UTNP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UTT": { - "address": "0x16f812Be7FfF02cAF662B85d5d58a5da6572D4Df", - "links": { - "Homepage": "https://uttoken.io" - }, - "marketcap_usd": 0, - "name": "United Traders Token", - "network": "eth", - "shortcut": "UTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:UUU": { - "address": "0x3543638eD4a9006E4840B105944271Bcea15605D", - "links": { - "Homepage": "https://u.network/" - }, - "marketcap_usd": 268098, - "name": "U Networks", - "network": "eth", - "shortcut": "UUU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VALOR": { - "address": "0x297E4e5e59Ad72B1B0A2fd446929e76117be0E0a", - "links": { - "Github": "https://github.com/smartvalor/ValorToken", - "Homepage": "https://smartvalor.com" - }, - "marketcap_usd": 4484748, - "name": "ValorToken", - "network": "eth", - "shortcut": "VALOR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VBX": { - "address": "0x6DCcF9C0aB71dAc26b7F7886E43a2B433806c590", - "links": { - "Github": "https://github.com/vibrantworkapp", - "Homepage": "http://www.vibrantworkapp.com" - }, - "marketcap_usd": 0, - "name": "vibrant", - "network": "eth", - "shortcut": "VBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VDG": { - "address": "0x57C75ECCc8557136D32619a191fBCDc88560d711", - "links": { - "Github": "https://github.com/VeriDocGlobal", - "Homepage": "https://www.veridocglobal.com/" - }, - "marketcap_usd": 1861173, - "name": "VeriDocGlobal", - "network": "eth", - "shortcut": "VDG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VDOC": { - "address": "0x82BD526bDB718C6d4DD2291Ed013A5186cAE2DCa", - "links": { - "Github": "https://github.com/BlueBikeSolutions", - "Homepage": "https://www.dutyof.care/token-launch/" - }, - "marketcap_usd": 0, - "name": "Duty of Care Token", - "network": "eth", - "shortcut": "VDOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VEE": { - "address": "0x340D2bdE5Eb28c1eed91B2f790723E3B160613B7", - "links": { - "Github": "https://github.com/blockv", - "Homepage": "https://blockv.io" - }, - "marketcap_usd": 9193229, - "name": "BLOCKv", - "network": "eth", - "shortcut": "VEE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VEGA": { - "address": "0xcB84d72e61e383767C4DFEb2d8ff7f4FB89abc6e", - "links": { - "Github": "https://github.com/vegaprotocol", - "Homepage": "https://vega.xyz" - }, - "marketcap_usd": 57183218, - "name": "Vega", - "network": "eth", - "shortcut": "VEGA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VEGAN": { - "address": "0xFADe17a07ba3B480aA1714c3724a52D4C57d410E", - "links": { - "Homepage": "https://www.vegancurrency.org" - }, - "marketcap_usd": 0, - "name": "Vegan", - "network": "eth", - "shortcut": "VEGAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VENUS": { - "address": "0xEbeD4fF9fe34413db8fC8294556BBD1528a4DAca", - "links": { - "Homepage": "http://venuscoin.net" - }, - "marketcap_usd": 0, - "name": "VENUS", - "network": "eth", - "shortcut": "VENUS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VERI": { - "address": "0x8f3470A7388c05eE4e7AF3d01D8C722b0FF52374", - "links": { - "Homepage": "https://veritas.veritaseum.com" - }, - "marketcap_usd": 67691562, - "name": "Veritaseum", - "network": "eth", - "shortcut": "VERI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIB": { - "address": "0x2C974B2d0BA1716E644c1FC59982a89DDD2fF724", - "links": { - "Homepage": "https://www.viberate.com" - }, - "marketcap_usd": 21389600, - "name": "Viberate", - "network": "eth", - "shortcut": "VIB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIBE": { - "address": "0xe8Ff5C9c75dEb346acAc493C463C8950Be03Dfba", - "links": { - "Homepage": "https://www.vibehub.io" - }, - "marketcap_usd": 448626, - "name": "VIBE Coin", - "network": "eth", - "shortcut": "VIBE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIBEX": { - "address": "0x882448f83d90B2bf477Af2eA79327fDEA1335D93", - "links": { - "Github": "https://github.com/amack2u/VibeHub", - "Homepage": "https://vibehub.io/ico/" - }, - "marketcap_usd": 0, - "name": "VIBEX Exchange Token", - "network": "eth", - "shortcut": "VIBEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VID": { - "address": "0x2C9023bBc572ff8dc1228c7858A280046Ea8C9E5", - "links": { - "Github": "https://github.com/videocoin", - "Homepage": "https://www.videocoin.io" - }, - "marketcap_usd": 4612359, - "name": "VideoCoin", - "network": "eth", - "shortcut": "VID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIDT": { - "address": "0x445f51299Ef3307dBD75036dd896565F5B4BF7A5", - "links": { - "Github": "https://github.com/V-ID/V-ID-Token", - "Homepage": "https://www.v-id.org" - }, - "marketcap_usd": 0, - "name": "V-ID Token", - "network": "eth", - "shortcut": "VIDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIEW": { - "address": "0xF03f8D65BaFA598611C3495124093c56e8F638f0", - "links": { - "Github": "https://github.com/Viewly/", - "Homepage": "https://view.ly/" - }, - "marketcap_usd": 0, - "name": "Viewly", - "network": "eth", - "shortcut": "VIEW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIKKY": { - "address": "0xd2946be786F35c3Cc402C29b323647aBda799071", - "links": { - "Homepage": "https://ico.vikky.io" - }, - "marketcap_usd": 60643, - "name": "VikkyToken", - "network": "eth", - "shortcut": "VIKKY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIT": { - "address": "0x23b75Bc7AaF28e2d6628C3f424B3882F8f072a3c", - "links": { - "Github": "https://github.com/ViceIndustryToken", - "Homepage": "https://vicetoken.com/" - }, - "marketcap_usd": 0, - "name": "Vice Industry Token", - "network": "eth", - "shortcut": "VIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VITE": { - "address": "0x1b793E49237758dBD8b752AFC9Eb4b329d5Da016", - "links": { - "Homepage": "https://www.vite.org" - }, - "marketcap_usd": 0, - "name": "Vite", - "network": "eth", - "shortcut": "VITE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VIU": { - "address": "0x519475b31653E46D20cD09F9FdcF3B12BDAcB4f5", - "links": { - "Github": "https://github.com/viuly", - "Homepage": "https://viuly.io" - }, - "marketcap_usd": 0, - "name": "Viuly", - "network": "eth", - "shortcut": "VIU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VLD": { - "address": "0x922aC473A3cC241fD3a0049Ed14536452D58D73c", - "links": { - "Github": "https://github.com/vetri-global/", - "Homepage": "https://vetri.global/" - }, - "marketcap_usd": 0, - "name": "VETRI", - "network": "eth", - "shortcut": "VLD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VMC": { - "address": "0xd811250b7fE83150cBB3d70a892fCE6189fB3e08", - "links": { - "Homepage": "https://vmccoin.com/" - }, - "marketcap_usd": 0, - "name": "Virtual Mind Chain", - "network": "eth", - "shortcut": "VMC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VN": { - "address": "0x00eA6f91B00E080e816f1bB2faD71b0fe1528983", - "links": { - "Homepage": "http://viroboss22.co" - }, - "marketcap_usd": 0, - "name": "VCOIN", - "network": "eth", - "shortcut": "VN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VNTY": { - "address": "0xC650f5514AE1A3a27930922145ce49E8A91b91AB", - "links": { - "Github": "https://github.com/venoty", - "Homepage": "https://venoty.com" - }, - "marketcap_usd": 0, - "name": "VENOTY", - "network": "eth", - "shortcut": "VNTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VNXLU": { - "address": "0x00fC270C9cc13e878Ab5363D00354bebF6f05C15", - "links": { - "Homepage": "https://vnx.io/" - }, - "marketcap_usd": 0, - "name": "VNX Exchange", - "network": "eth", - "shortcut": "VNXLU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VOC": { - "address": "0xc3bC9Eb71f75Ec439A6b6C8E8b746fCF5b62F703", - "links": { - "Github": "https://github.com/vormacoin", - "Homepage": "https://vormacoin.io/" - }, - "marketcap_usd": 0, - "name": "VORMACOIN", - "network": "eth", - "shortcut": "VOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VOISE": { - "address": "0x83eEA00D838f92dEC4D1475697B9f4D3537b56E3", - "links": { - "Homepage": "https://voise.it" - }, - "marketcap_usd": 0, - "name": "Voise", - "network": "eth", - "shortcut": "VOISE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VR": { - "address": "0x7d5121505149065b562C789A0145eD750e6E8cdD", - "links": { - "Homepage": "https://victoriavr.com/" - }, - "marketcap_usd": 11153234, - "name": "Victoria VR", - "network": "eth", - "shortcut": "VR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VRE": { - "address": "0xF722B01910F93B84EDa9CA128b9F05821A41EAe1", - "links": { - "Homepage": "https://www.vrenelium.com" - }, - "marketcap_usd": 0, - "name": "Vrenelium", - "network": "eth", - "shortcut": "VRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VRO": { - "address": "0x10BC518c32fbAE5e38Ecb50A612160571bD81e44", - "links": { - "Homepage": "https://veraone.io/" - }, - "marketcap_usd": 0, - "name": "VeraOne", - "network": "eth", - "shortcut": "VRO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VSF": { - "address": "0xBA3a79D758f19eFe588247388754b8e4d6EddA81", - "links": { - "Github": "https://github.com/VeriSafe", - "Homepage": "https://verisafe.io/" - }, - "marketcap_usd": 0, - "name": "VeriSafe", - "network": "eth", - "shortcut": "VSF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VSL": { - "address": "0x5c543e7AE0A1104f78406C340E9C64FD9fCE5170", - "links": { - "Homepage": "https://www.vdice.io" - }, - "marketcap_usd": 0, - "name": "Vdice", - "network": "eth", - "shortcut": "VSL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VUU": { - "address": "0x4b96bf1feF93A216914fc843D81207A027ce52b3", - "links": { - "Github": "https://github.com/Vuulr", - "Homepage": "https://www.vuulr.com/" - }, - "marketcap_usd": 0, - "name": "Vuulr Token", - "network": "eth", - "shortcut": "VUU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:VZT": { - "address": "0x9720b467a710382A232a32F540bDCed7d662a10B", - "links": { - "Homepage": "https://vezt.co" - }, - "marketcap_usd": 0, - "name": "Vezt", - "network": "eth", - "shortcut": "VZT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WAB": { - "address": "0x4BBbC57aF270138Ef2FF2C50DbfAD684e9E0e604", - "links": { - "Homepage": "https://wab.network" - }, - "marketcap_usd": 276519, - "name": "WABnetwork", - "network": "eth", - "shortcut": "WAB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WABI": { - "address": "0x286BDA1413a2Df81731D4930ce2F862a35A609fE", - "links": { - "Homepage": "https://taelpay.com" - }, - "marketcap_usd": 13590697, - "name": "Tael", - "network": "eth", - "shortcut": "WABI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WAK": { - "address": "0x9f6513ED2b0DE89218E97DB4A5115ba04Be449f1", - "links": { - "Github": "https://github.com/WakCoin", - "Homepage": "https://wakcoin.com" - }, - "marketcap_usd": 0, - "name": "Wak Coin", - "network": "eth", - "shortcut": "WAK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WATT": { - "address": "0x829A4cA1303383F1082B6B1fB937116e4b3b5605", - "links": { - "Github": "https://github.com/workchainio", - "Homepage": "https://workchain.io/" - }, - "marketcap_usd": 0, - "name": "WorkChain App Token", - "network": "eth", - "shortcut": "WATT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WAX": { - "address": "0x39Bb259F66E1C59d5ABEF88375979b4D20D98022", - "links": { - "Github": "https://github.com/waxio", - "Homepage": "https://wax.io" - }, - "marketcap_usd": 0, - "name": "WAX", - "network": "eth", - "shortcut": "WAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WAY": { - "address": "0x217f96737b39f9b9211767cb6aeF5DbAe2Fe9402", - "links": { - "Github": "https://github.com/waybazaar", - "Homepage": "https://waybazaar.co" - }, - "marketcap_usd": 0, - "name": "Bazaar Gift Token", - "network": "eth", - "shortcut": "WAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WBA": { - "address": "0x74951B677de32D596EE851A233336926e6A2cd09", - "links": { - "Homepage": "http://webetcrypto.io/wbc" - }, - "marketcap_usd": 0, - "name": "WeBetCrypto", - "network": "eth", - "shortcut": "WBA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WBTC": { - "address": "0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599", - "links": { - "Github": "https://github.com/WrappedBTC", - "Homepage": "https://wbtc.network" - }, - "marketcap_usd": 3841396768, - "name": "Wrapped Bitcoin", - "network": "eth", - "shortcut": "WBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WBX": { - "address": "0xbB97e381F1d1e94ffa2A5844F6875e6146981009", - "links": { - "Github": "https://github.com/wibxcoin/Contracts", - "Homepage": "https://www.wibx.io" - }, - "marketcap_usd": 0, - "name": "WiBX Utility Token", - "network": "eth", - "shortcut": "WBX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WCN": { - "address": "0x8F936fE0faF0604c9C0Ef2406bde0A65365515d6", - "links": { - "Github": "https://github.com/WorldCoinNetwork", - "Homepage": "https://worldcoin.cash/" - }, - "marketcap_usd": 0, - "name": "WorldCoinNetwork", - "network": "eth", - "shortcut": "WCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WCT": { - "address": "0x6a0A97E47d15aAd1D132a1Ac79a480E3F2079063", - "links": { - "Homepage": "https://wepower.network" - }, - "marketcap_usd": 0, - "name": "WePower", - "network": "eth", - "shortcut": "WCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WDOGE": { - "address": "0x8aa9381b2544b48c26f3b850F6e07E2c5161EB3e", - "links": { - "Github": "https://github.com/WrappedBTC/bitcoin-token-smart-contracts/blob/master/ethereumV2/contracts/token/WDOGE.sol", - "Homepage": "https://wdoge.tech/" - }, - "marketcap_usd": 0, - "name": "Wrapped DOGE", - "network": "eth", - "shortcut": "WDOGE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WEB": { - "address": "0x840fe75ABfaDc0F2d54037829571B2782e919ce4", - "links": { - "Homepage": "https://webcoin.today" - }, - "marketcap_usd": 0, - "name": "Webcoin", - "network": "eth", - "shortcut": "WEB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WETH": { - "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", - "links": { - "Homepage": "https://weth.io" - }, - "marketcap_usd": 0, - "name": "WETH", - "network": "eth", - "shortcut": "WETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WHEN": { - "address": "0xF4FE95603881D0e07954fD7605E0e9a916e42C44", - "links": { - "Github": "https://github.com/WhenHub", - "Homepage": "https://interface.whenhub.com" - }, - "marketcap_usd": 0, - "name": "WHEN Token", - "network": "eth", - "shortcut": "WHEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WIB": { - "address": "0x3F17Dd476faF0a4855572F0B6ed5115D9bBA22AD", - "links": { - "Github": "https://github.com/wibsonorg", - "Homepage": "https://wibson.org" - }, - "marketcap_usd": 0, - "name": "Wibson Token", - "network": "eth", - "shortcut": "WIB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WILC": { - "address": "0xC98a910eDE52E7d5308525845F19e17470DbCCF7", - "links": { - "Homepage": "https://ilcoincrypto.com/" - }, - "marketcap_usd": 0, - "name": "Wrapped ILCOIN", - "network": "eth", - "shortcut": "WILC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WILD": { - "address": "0xD3C00772B24D997A812249ca637a921e81357701", - "links": { - "Github": "https://github.com/WildCryptoICO/Wild-Crypto-Token", - "Homepage": "http://www.wildcrypto.com" - }, - "marketcap_usd": 0, - "name": "WILD Token", - "network": "eth", - "shortcut": "WILD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WINGS": { - "address": "0x667088b212ce3d06a1b553a7221E1fD19000d9aF", - "links": { - "Homepage": "https://wings.ai" - }, - "marketcap_usd": 176076, - "name": "WINGS", - "network": "eth", - "shortcut": "WINGS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WISH": { - "address": "0x1b22C32cD936cB97C28C5690a0695a82Abf688e6", - "links": { - "Homepage": "https://mywish.io" - }, - "marketcap_usd": 0, - "name": "MyWish", - "network": "eth", - "shortcut": "WISH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WLKR": { - "address": "0xD64DeEA5F24934E3A1aa752912aEe8ffD8300C3F", - "links": { - "Github": "https://github.com/wlkrfinancial", - "Homepage": "https://wlkr.finance/ " - }, - "marketcap_usd": 0, - "name": "WLKR Innovation Index", - "network": "eth", - "shortcut": "WLKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WLKRR": { - "address": "0xC90206AB21bdbF5e92AfF4E6B5F097B65b0eCc06", - "links": { - "Github": "https://github.com/wlkrfinancial", - "Homepage": "https://wlkr.finance" - }, - "marketcap_usd": 0, - "name": "Walker", - "network": "eth", - "shortcut": "WLKRR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WMA": { - "address": "0x685ED390B16Ac9Df9Ab9707294a42a107cFB62Af", - "links": { - "Homepage": "https://www.weemat.io" - }, - "marketcap_usd": 0, - "name": "weeMarketplaceAccessToken", - "network": "eth", - "shortcut": "WMA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WMK": { - "address": "0xBFbe5332f172d77811bC6c272844f3e54A7B23bB", - "links": { - "Github": "https://github.com/WemarkSource", - "Homepage": "https://www.wemark.com" - }, - "marketcap_usd": 0, - "name": "WemarkToken", - "network": "eth", - "shortcut": "WMK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WOC": { - "address": "0xF9D9702D031407F425a4412682fDc56b07d05262", - "links": { - "Github": "https://github.com/paneedesign/wallofchain", - "Homepage": "https://wallofchain.com" - }, - "marketcap_usd": 0, - "name": "WallOfChain", - "network": "eth", - "shortcut": "WOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WOUSD": { - "address": "0xD2af830E8CBdFed6CC11Bab697bB25496ed6FA62", - "links": { - "Github": "https://github.com/OriginProtocol/origin-dollar", - "Homepage": "https://www.ousd.com" - }, - "marketcap_usd": 0, - "name": "Wrapped OUSD", - "network": "eth", - "shortcut": "WOUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WPC": { - "address": "0x62087245087125d3DB5B9A3D713d78E7BBc31e54", - "links": { - "Homepage": "http://www.worldpeacecoin.io" - }, - "marketcap_usd": 0, - "name": "WorldPeaceCoin", - "network": "eth", - "shortcut": "WPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WPR": { - "address": "0x4CF488387F035FF08c371515562CBa712f9015d4", - "links": { - "Homepage": "https://wepower.network" - }, - "marketcap_usd": 166674, - "name": "WePower Token", - "network": "eth", - "shortcut": "WPR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WRC": { - "address": "0x72aDadb447784dd7AB1F472467750fC485e4cb2d", - "links": { - "Homepage": "https://worldcore.eu" - }, - "marketcap_usd": 59023, - "name": "Worldcore", - "network": "eth", - "shortcut": "WRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WRK": { - "address": "0x71e8d74fF1C923E369D0e70DFb09866629C4DD35", - "links": { - "Github": "https://github.com/TMWorkCoin", - "Homepage": "https://workcoin.net/" - }, - "marketcap_usd": 0, - "name": "WorkCoin", - "network": "eth", - "shortcut": "WRK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WSS": { - "address": "0x1d9a3CeF66B01D44003b9db0e00ec3fd44746988", - "links": { - "Github": "https://github.com/wealthsharingsystems", - "Homepage": "https://res.cloudinary.com/cloudimgstorage/image/upload/v1561127947/WSS-LOGO.png" - }, - "marketcap_usd": 0, - "name": "ETHWSS Coin", - "network": "eth", - "shortcut": "WSS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WWX": { - "address": "0x8A91eEcd3F6b6B7833fD6961E7f654C3d016a068", - "links": { - "Github": "https://github.com/wowoo-exchange/WWX-ERC20", - "Homepage": "https://wowoo.exchange/" - }, - "marketcap_usd": 0, - "name": "Wowoo Exchange Token", - "network": "eth", - "shortcut": "WWX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WYS": { - "address": "0xd8950fDeaa10304B7A7Fd03a2FC66BC39f3c711a", - "links": { - "Github": "https://github.com/wysker", - "Homepage": "https://www.wystoken.org" - }, - "marketcap_usd": 0, - "name": "wystoken", - "network": "eth", - "shortcut": "WYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:WYV": { - "address": "0x056017c55aE7AE32d12AeF7C679dF83A85ca75Ff", - "links": { - "Github": "https://github.com/ProjectWyvern", - "Homepage": "https://projectwyvern.com" - }, - "marketcap_usd": 0, - "name": "WyvernToken", - "network": "eth", - "shortcut": "WYV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:X8X": { - "address": "0x910Dfc18D6EA3D6a7124A6F8B5458F281060fa4c", - "links": { - "Homepage": "https://x8currency.com" - }, - "marketcap_usd": 529029, - "name": "X8X", - "network": "eth", - "shortcut": "X8X", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XAMP": { - "address": "0xf911a7ec46a2c6fa49193212fe4a2a9B95851c27", - "links": { - "Homepage": "https://www.antiample.org/" - }, - "marketcap_usd": 0, - "name": "Antiample", - "network": "eth", - "shortcut": "XAMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XAUR": { - "address": "0x4DF812F6064def1e5e029f1ca858777CC98D2D81", - "links": { - "Homepage": "http://www.xaurum.org" - }, - "marketcap_usd": 1880493, - "name": "Xaurum", - "network": "eth", - "shortcut": "XAUR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XBL": { - "address": "0x49AeC0752E68D0282Db544C677f6BA407BA17ED7", - "links": { - "Homepage": "https://billionairetoken.com" - }, - "marketcap_usd": 0, - "name": "Billionaire Token", - "network": "eth", - "shortcut": "XBL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XBP": { - "address": "0x28dee01D53FED0Edf5f6E310BF8Ef9311513Ae40", - "links": { - "Github": "https://github.com/blitzpredict", - "Homepage": "https://www.blitzpredict.io" - }, - "marketcap_usd": 58228, - "name": "BlitzPredict", - "network": "eth", - "shortcut": "XBP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XCC": { - "address": "0x4d829f8C92a6691c56300D020c9e0dB984Cfe2BA", - "links": { - "Github": "https://github.com/coincrowd-it", - "Homepage": "https://www.coincrowd.it" - }, - "marketcap_usd": 0, - "name": "CoinCrowd", - "network": "eth", - "shortcut": "XCC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XCHF": { - "address": "0xB4272071eCAdd69d933AdcD19cA99fe80664fc08", - "links": { - "Homepage": "https://www.swisscryptotokens.ch/" - }, - "marketcap_usd": 3302072, - "name": "CryptoFranc", - "network": "eth", - "shortcut": "XCHF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XCL": { - "address": "0x0843971B4ac6e842a518AA184e0271d88B5cB74F", - "links": { - "Github": "https://github.com/classieprojects", - "Homepage": "https://www.classify.global" - }, - "marketcap_usd": 0, - "name": "CLASSIE", - "network": "eth", - "shortcut": "XCL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XCLR": { - "address": "0x1E26b3D07E57F453caE30F7DDd2f945f5bF3EF33", - "links": { - "Homepage": "https://clearcoin.co" - }, - "marketcap_usd": 0, - "name": "ClearCoin", - "network": "eth", - "shortcut": "XCLR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XDATA": { - "address": "0x0Cf0Ee63788A0849fE5297F3407f701E122cC023", - "links": { - "Github": "https://github.com/streamr-dev", - "Homepage": "https://www.streamr.com" - }, - "marketcap_usd": 0, - "name": "Streamr DATAcoin", - "network": "eth", - "shortcut": "XDATA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XDCE": { - "address": "0x41AB1b6fcbB2fA9DCEd81aCbdeC13Ea6315F2Bf2", - "links": { - "Homepage": "https://www.xinfin.io" - }, - "marketcap_usd": 0, - "name": "XinFin Network", - "network": "eth", - "shortcut": "XDCE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XES": { - "address": "0xA017ac5faC5941f95010b12570B812C974469c2C", - "links": { - "Homepage": "https://proxeus.com" - }, - "marketcap_usd": 0, - "name": "Proxeus", - "network": "eth", - "shortcut": "XES", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XET": { - "address": "0x054C64741dBafDC19784505494029823D89c3b13", - "links": { - "Homepage": "https://www.atom-solutions.jp/en/xetchange.php" - }, - "marketcap_usd": 0, - "name": "ETERNAL TOKEN", - "network": "eth", - "shortcut": "XET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XFS": { - "address": "0x16aF5bfb4Ae7E475b9aDC3Bf5Cb2f1E6a50d7940", - "links": { - "Homepage": "http://fanship.world/" - }, - "marketcap_usd": 0, - "name": "Fanship", - "network": "eth", - "shortcut": "XFS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XGG": { - "address": "0xf6b6AA0Ef0f5Edc2C1c5d925477F97eAF66303e7", - "links": { - "Github": "https://github.com/GoingGems", - "Homepage": "https://www.going-gems.com" - }, - "marketcap_usd": 0, - "name": "Going Gems", - "network": "eth", - "shortcut": "XGG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XGM": { - "address": "0x533ef0984b2FAA227AcC620C67cce12aA39CD8CD", - "links": { - "Homepage": "https://www.xaurum.org/gamma" - }, - "marketcap_usd": 0, - "name": "XGM", - "network": "eth", - "shortcut": "XGM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XGT": { - "address": "0x30f4A3e0aB7a76733D8b60b89DD93c3D0b4c9E2f", - "links": { - "Github": "https://github.com/CryptogeneProject/CryptogeneToken", - "Homepage": "https://cryptogene.co" - }, - "marketcap_usd": 0, - "name": "XGT", - "network": "eth", - "shortcut": "XGT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XHT": { - "address": "0xD3c625F54dec647DB8780dBBe0E880eF21BA4329", - "links": { - "Github": "https://github.com/bitholla", - "Homepage": "https://hollaex.com" - }, - "marketcap_usd": 0, - "name": "HollaEx", - "network": "eth", - "shortcut": "XHT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XID": { - "address": "0xB110eC7B1dcb8FAB8dEDbf28f53Bc63eA5BEdd84", - "links": { - "Homepage": "https://sphereidentity.com" - }, - "marketcap_usd": 0, - "name": "Sphere Identity", - "network": "eth", - "shortcut": "XID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XIO": { - "address": "0x0f7F961648aE6Db43C75663aC7E5414Eb79b5704", - "links": { - "Homepage": "https://xio.network/" - }, - "marketcap_usd": 244530, - "name": "XIO Network", - "network": "eth", - "shortcut": "XIO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XLX": { - "address": "0x1d086b868d78040635CB8600bA733f12DB48cB42", - "links": { - "Github": "https://github.com/XLXPAY", - "Homepage": "https://xlxpay.com" - }, - "marketcap_usd": 0, - "name": "XLXPay", - "network": "eth", - "shortcut": "XLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XMCT": { - "address": "0x44449Fa4d607F807d1eD4a69ad942971728391C8", - "links": { - "Homepage": "http://xmedchain.com" - }, - "marketcap_usd": 0, - "name": "XMED Chain", - "network": "eth", - "shortcut": "XMCT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XMX": { - "address": "0x0f8c45B896784A1E408526B9300519ef8660209c", - "links": { - "Github": "https://github.com/XMaxPlatform", - "Homepage": "https://www.xmx.com" - }, - "marketcap_usd": 304015, - "name": "XMax", - "network": "eth", - "shortcut": "XMX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XNK": { - "address": "0xBC86727E770de68B1060C91f6BB6945c73e10388", - "links": { - "Github": "https://github.com/InkProtocol/", - "Homepage": "https://paywithink.com" - }, - "marketcap_usd": 0, - "name": "Ink Protocol", - "network": "eth", - "shortcut": "XNK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XNN": { - "address": "0xab95E915c123fdEd5BDfB6325e35ef5515F1EA69", - "links": { - "Homepage": "https://xenon.network" - }, - "marketcap_usd": 0, - "name": "XENON", - "network": "eth", - "shortcut": "XNN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XNT": { - "address": "0x572E6f318056ba0C5d47A422653113843D250691", - "links": { - "Homepage": "https://exante.eu" - }, - "marketcap_usd": 0, - "name": "XNT", - "network": "eth", - "shortcut": "XNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XOV": { - "address": "0x153eD9CC1b792979d2Bde0BBF45CC2A7e436a5F9", - "links": { - "Homepage": "http://www.xov.io" - }, - "marketcap_usd": 4613, - "name": "XOVBank", - "network": "eth", - "shortcut": "XOV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XPA": { - "address": "0x90528aeb3a2B736B780fD1B6C478bB7E1d643170", - "links": { - "Homepage": "https://xpa.io" - }, - "marketcap_usd": 32562, - "name": "XPA", - "network": "eth", - "shortcut": "XPA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XPAT": { - "address": "0xBB1fA4FdEB3459733bF67EbC6f893003fA976a82", - "links": { - "Github": "https://github.com/Bit-Nation/", - "Homepage": "https://bitnation.co" - }, - "marketcap_usd": 0, - "name": "Pangea Arbitration Token", - "network": "eth", - "shortcut": "XPAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XPAY": { - "address": "0xbC7Ed0c8cf986ae62337fc8DF3B02C6EC87310Ed", - "links": { - "Github": "https://github.com/xpayment", - "Homepage": "http://xpayment.de" - }, - "marketcap_usd": 0, - "name": "Xpayment", - "network": "eth", - "shortcut": "XPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XPR": { - "address": "0xD7EFB00d12C2c13131FD319336Fdf952525dA2af", - "links": { - "Github": "https://github.com/ProtonProtocol", - "Homepage": "https://www.protonchain.com/" - }, - "marketcap_usd": 24851023, - "name": "Proton", - "network": "eth", - "shortcut": "XPR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XPT": { - "address": "0x08Aa0ed0040736dd28d4c8B16Ab453b368248d19", - "links": { - "Homepage": "https://cryptobuyer.io" - }, - "marketcap_usd": 0, - "name": "Cryptobuyer Token", - "network": "eth", - "shortcut": "XPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XRL": { - "address": "0xB24754bE79281553dc1adC160ddF5Cd9b74361a4", - "links": { - "Homepage": "https://rialto.ai" - }, - "marketcap_usd": 0, - "name": "XRL", - "network": "eth", - "shortcut": "XRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XSC": { - "address": "0x0F513fFb4926ff82D7F60A05069047AcA295C413", - "links": { - "Homepage": "http://crowdstart.capital" - }, - "marketcap_usd": 0, - "name": "XSC", - "network": "eth", - "shortcut": "XSC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XSGD": { - "address": "0x70e8dE73cE538DA2bEEd35d14187F6959a8ecA96", - "links": { - "Github": "https://github.com/Xfers/StraitsX-tokens", - "Homepage": "https://xfers.com/sg/stablecoin" - }, - "marketcap_usd": 59730862, - "name": "Singapore-Dollar Backed Stablecoin", - "network": "eth", - "shortcut": "XSGD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:XYO": { - "address": "0x55296f69f40Ea6d20E478533C15A6B08B654E758", - "links": { - "Homepage": "https://xyo.network" - }, - "marketcap_usd": 72604094, - "name": "XYO", - "network": "eth", - "shortcut": "XYO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YAM": { - "address": "0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16", - "links": { - "Github": "https://github.com/yam-finance/yam-protocol", - "Homepage": "http://yam.finance/" - }, - "marketcap_usd": 0, - "name": "YAM V1", - "network": "eth", - "shortcut": "YAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YAMv2": { - "address": "0xAba8cAc6866B83Ae4eec97DD07ED254282f6aD8A", - "links": { - "Github": "https://github.com/yam-finance/yam-protocol", - "Homepage": "http://yam.finance/" - }, - "marketcap_usd": 0, - "name": "YAM V2", - "network": "eth", - "shortcut": "YAMv2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YEE": { - "address": "0x922105fAd8153F516bCfB829f56DC097a0E1D705", - "links": { - "Homepage": "http://www.yeefoundation.com" - }, - "marketcap_usd": 244413, - "name": "Yee Token", - "network": "eth", - "shortcut": "YEE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YFI": { - "address": "0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e", - "links": { - "Github": "https://github.com/iearn-finance", - "Homepage": "https://yearn.finance/" - }, - "marketcap_usd": 341339987, - "name": "yearn.finance", - "network": "eth", - "shortcut": "YFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YFII": { - "address": "0xa1d0E215a23d7030842FC67cE582a6aFa3CCaB83", - "links": { - "Github": "https://github.com/yfii/vault", - "Homepage": "https://dfi.money/" - }, - "marketcap_usd": 50523406, - "name": "YFII.finance", - "network": "eth", - "shortcut": "YFII", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YFV": { - "address": "0x45f24BaEef268BB6d63AEe5129015d69702BCDfa", - "links": { - "Github": "https://github.com/yfv-finance/audit", - "Homepage": "https://yfv.finance/" - }, - "marketcap_usd": 0, - "name": "YFValue", - "network": "eth", - "shortcut": "YFV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YOUC": { - "address": "0x3D371413dd5489F3A04C07c0C2CE369c20986ceb", - "links": { - "Github": "https://github.com/YOUengine", - "Homepage": "https://youengine.io" - }, - "marketcap_usd": 0, - "name": "yOUcash", - "network": "eth", - "shortcut": "YOUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:YTRO": { - "address": "0x534546C490A4Ed2a9D0c3555447Bb9b4b01bcb9E", - "links": { - "Github": "https://github.com/IamYotro", - "Homepage": "http://yotro.io" - }, - "marketcap_usd": 0, - "name": "Yotro", - "network": "eth", - "shortcut": "YTRO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZAP": { - "address": "0x6781a0F84c7E9e846DCb84A9a5bd49333067b104", - "links": { - "Github": "https://github.com/zapproject", - "Homepage": "https://zap.store" - }, - "marketcap_usd": 842523, - "name": "ZAP", - "network": "eth", - "shortcut": "ZAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZCN": { - "address": "0xb9EF770B6A5e12E45983C5D80545258aA38F3B78", - "links": { - "Homepage": "https://0chain.net" - }, - "marketcap_usd": 10060329, - "name": "0chain", - "network": "eth", - "shortcut": "ZCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZCO": { - "address": "0x2008e3057BD734e10AD13c9EAe45Ff132aBc1722", - "links": { - "Homepage": "https://www.zebi.io" - }, - "marketcap_usd": 0, - "name": "Zebi", - "network": "eth", - "shortcut": "ZCO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZCS": { - "address": "0x7A41e0517a5ecA4FdbC7FbebA4D4c47B9fF6DC63", - "links": { - "Homepage": "https://zsc.io/" - }, - "marketcap_usd": 93153, - "name": "Zeusshield", - "network": "eth", - "shortcut": "ZCS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZDC": { - "address": "0x7A2810d3d859Ed03ede523eB801a3B43B5e8979C", - "links": { - "Homepage": "https://zodcoin.net" - }, - "marketcap_usd": 0, - "name": "Zodcoin", - "network": "eth", - "shortcut": "ZDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZENI": { - "address": "0x2E59D147962E2bB3fBdc52dc18CfBa2653C06Ccc", - "links": { - "Homepage": "https://thesevensofficial.com/" - }, - "marketcap_usd": 0, - "name": "Zeni Token", - "network": "eth", - "shortcut": "ZENI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZERA": { - "address": "0x8188e51Bc678F0070531f0e782718Df0027452De", - "links": { - "Github": "https://github.com/zinvest", - "Homepage": "http://zeraco.in" - }, - "marketcap_usd": 0, - "name": "ZERACOIN", - "network": "eth", - "shortcut": "ZERA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZEUS": { - "address": "0xe7E4279b80D319EDe2889855135A22021baf0907", - "links": { - "Github": "https://github.com/ZEUS-coin", - "Homepage": "https://zeusfundme.com/" - }, - "marketcap_usd": 0, - "name": "ZeusNetwork", - "network": "eth", - "shortcut": "ZEUS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZINC": { - "address": "0x4AaC461C86aBfA71e9d00d9a2cde8d74E4E1aeEa", - "links": { - "Homepage": "https://zinc.work" - }, - "marketcap_usd": 5020, - "name": "ZINC", - "network": "eth", - "shortcut": "ZINC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZIP": { - "address": "0xA9d2927d3a04309E008B6af6E2e282AE2952e7fD", - "links": { - "Homepage": "http://zipper.io" - }, - "marketcap_usd": 0, - "name": "Zipper", - "network": "eth", - "shortcut": "ZIP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZIPT": { - "address": "0xEDD7c94FD7B4971b916d15067Bc454b9E1bAD980", - "links": { - "Homepage": "https://zippie.org" - }, - "marketcap_usd": 0, - "name": "Zippie", - "network": "eth", - "shortcut": "ZIPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZIX": { - "address": "0xf3C092cA8CD6D3d4ca004Dc1d0f1fe8CcAB53599", - "links": { - "Github": "https://github.com/Zeexme", - "Homepage": "https://zeex.me" - }, - "marketcap_usd": 0, - "name": "ZIX", - "network": "eth", - "shortcut": "ZIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZLA": { - "address": "0xfd8971d5E8E1740cE2d0A84095fCA4De729d0c16", - "links": { - "Homepage": "https://zla.io" - }, - "marketcap_usd": 0, - "name": "Zilla", - "network": "eth", - "shortcut": "ZLA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZMAN": { - "address": "0xE25FAAb5821ce70BA4179A70c1d481BA45b9D0c9", - "links": { - "Github": "https://github.com/zmandotcom", - "Homepage": "https://www.zman.com" - }, - "marketcap_usd": 0, - "name": "ZMAN Coin", - "network": "eth", - "shortcut": "ZMAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZMN": { - "address": "0x554FFc77F4251a9fB3c0E3590a6a205f8d4e067D", - "links": { - "Homepage": "https://www.zmine.com" - }, - "marketcap_usd": 0, - "name": "ZMINE", - "network": "eth", - "shortcut": "ZMN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZPR": { - "address": "0xb5b8F5616Fe42d5ceCA3e87F3FddbDd8F496d760", - "links": { - "Homepage": "https://zper.io" - }, - "marketcap_usd": 0, - "name": "ZPER", - "network": "eth", - "shortcut": "ZPR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZRX": { - "address": "0xE41d2489571d322189246DaFA5ebDe1F4699F498", - "links": { - "Github": "https://github.com/0xProject", - "Homepage": "https://0xproject.com" - }, - "marketcap_usd": 222664444, - "name": "0x Project", - "network": "eth", - "shortcut": "ZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZST": { - "address": "0xe386B139Ed3715Ca4B18Fd52671bDcea1cdFE4b1", - "links": { - "Homepage": "http://zeus.exchange" - }, - "marketcap_usd": 0, - "name": "Zeus Exchange", - "network": "eth", - "shortcut": "ZST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:ZXC": { - "address": "0x83e2BE8d114F9661221384B3a50d24B96a5653F5", - "links": { - "Homepage": "https://0xcert.org" - }, - "marketcap_usd": 0, - "name": "0xcert Protocol Token", - "network": "eth", - "shortcut": "ZXC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cBAT": { - "address": "0x6C8c6b02E7b2BE14d4fA6022Dfd6d75921D90E4E", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound Basic Attention Token", - "network": "eth", - "shortcut": "cBAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cETH": { - "address": "0x4Ddc2D193948926D02f9B1fE9e1daa0718270ED5", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound Ether", - "network": "eth", - "shortcut": "cETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cREP": { - "address": "0x158079Ee67Fce2f58472A96584A73C7Ab9AC95c1", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound Augur", - "network": "eth", - "shortcut": "cREP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cSai": { - "address": "0xF5DCe57282A584D2746FaF1593d3121Fcac444dC", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound Sai", - "network": "eth", - "shortcut": "cSai", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cUSDC": { - "address": "0x39AA39c021dfbaE8faC545936693aC917d5E7563", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound USDCoin", - "network": "eth", - "shortcut": "cUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cV": { - "address": "0xdA6cb58A0D0C01610a29c5A65c303e13e885887C", - "links": { - "Github": "https://github.com/carVertical", - "Homepage": "https://www.carvertical.com" - }, - "marketcap_usd": 0, - "name": "carVertical", - "network": "eth", - "shortcut": "cV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cWBTC": { - "address": "0xC11b1268C1A384e55C48c2391d8d480264A3A7F4", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound Wrapped BTC", - "network": "eth", - "shortcut": "cWBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:cZRX": { - "address": "0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407", - "links": { - "Github": "https://github.com/compound-finance/", - "Homepage": "https://app.compound.finance" - }, - "marketcap_usd": 0, - "name": "Compound 0x", - "network": "eth", - "shortcut": "cZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLBAT2x": { - "address": "0x6F3a5DCc36eEee5bd8B9B5Db3B6431187A8F1E17", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 2x", - "network": "eth", - "shortcut": "dLBAT2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLBAT3x": { - "address": "0xE7bEd2E5FcA01F13E8230BF9b67963Ad231B81A6", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 3x", - "network": "eth", - "shortcut": "dLBAT3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLBAT4x": { - "address": "0x8880F71Fe078Aa1C5bBf8A5FF6Fb93E475a9FcE3", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 4x", - "network": "eth", - "shortcut": "dLBAT4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLKNC2x": { - "address": "0x5C24F19f91F4eA8A3F95cB21EbBeA053446D8632", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 3x", - "network": "eth", - "shortcut": "dLKNC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLKNC3x": { - "address": "0x9B70e6AaC469c75f4044C78d416eE3bc1a92ac22", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long KNC 3x", - "network": "eth", - "shortcut": "dLKNC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLKNC4x": { - "address": "0x7FD75AC96cA1f0aFfA154fbC1ae08752D4880E83", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long KNC 4x", - "network": "eth", - "shortcut": "dLKNC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLLINK2x": { - "address": "0x1abb24C9c806eAA71750Fa05C4009bd32e65ebad", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long LINK-DAI 2x v2", - "network": "eth", - "shortcut": "dLLINK2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLLINK3x": { - "address": "0x92bA756169aA6Ff82a3d6ae8e4456A5883182Fa3", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long LINK-DAI 3x v2 ", - "network": "eth", - "shortcut": "dLLINK3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLLINK4x": { - "address": "0x3789A8cAc9D2Eb3Cb87c09CA3422b928c768b362", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long LINK-DAI 4x v2 ", - "network": "eth", - "shortcut": "dLLINK4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLREP2x": { - "address": "0xfD6C76546d93e6120Eb6Eaa266966F51330280C3", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 2x", - "network": "eth", - "shortcut": "dLREP2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLREP3x": { - "address": "0xAF16308808361b203d4eD521cdde6dd2e9B168F0", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 3x", - "network": "eth", - "shortcut": "dLREP3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLREP4x": { - "address": "0x240fe85447A878f51A74A5dC0b644b4A72587839", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 4x", - "network": "eth", - "shortcut": "dLREP4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLWBTC2x": { - "address": "0x9fe6854447bB39dc8b78960882831269f9e78408", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 2x", - "network": "eth", - "shortcut": "dLWBTC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLWBTC3x": { - "address": "0x6d08B86002221Dc2fE4e27170fF90e1B92de3254", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 3x", - "network": "eth", - "shortcut": "dLWBTC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLWBTC4x": { - "address": "0x4F4D523C69a47c5C3ef06c53ec64801f11a884Dd", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 4x", - "network": "eth", - "shortcut": "dLWBTC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLZRX2x": { - "address": "0x1B7395d7D8B289a78920A87ce12160BaCd304C51", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ZRX 2x", - "network": "eth", - "shortcut": "dLZRX2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLZRX3x": { - "address": "0x2A93cBeC0D134205c352d92d81BB7c4Ec5Ef4d4e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ZRX 3x", - "network": "eth", - "shortcut": "dLZRX3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dLZRX4x": { - "address": "0xf85753Fb0Dc0A6c9B4F230eb861708677ac3C00f", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT", - "network": "eth", - "shortcut": "dLZRX4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsBAT": { - "address": "0x2A40251ba733F10835447a8fcf0e0f1CE658F18A", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT", - "network": "eth", - "shortcut": "dsBAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsBAT2x": { - "address": "0x143b591DE9CFf2BaFFB717aC0d109Bc5C01e203e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 2x", - "network": "eth", - "shortcut": "dsBAT2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsBAT3x": { - "address": "0x83A0dC31700Af1772B7Ea84Fde7675ca6021b5dA", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 3x", - "network": "eth", - "shortcut": "dsBAT3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsBAT4x": { - "address": "0xc37a0d81D9610514db1047dE52e9A9093530D2E4", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 4x", - "network": "eth", - "shortcut": "dsBAT4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsKNC": { - "address": "0x692a2b8bE7E166D6EE93B22A4B8B351e5d444339", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 2x", - "network": "eth", - "shortcut": "dsKNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsKNC2x": { - "address": "0x30BB2D30B3A3A3F4943f81d460b45D2dac5735DF", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 2x", - "network": "eth", - "shortcut": "dsKNC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsKNC3x": { - "address": "0x5E9188280e1e35aE8F899b09C97558d0F195cC14", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 3x", - "network": "eth", - "shortcut": "dsKNC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsKNC4x": { - "address": "0x4665A6F4F78bc13ACECB328f5f22f0e4e66D2285", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 4x", - "network": "eth", - "shortcut": "dsKNC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsLINK": { - "address": "0xAabFD407F367b632022b4bDe289D9c85F1A024d2", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short LINK-DAI v2", - "network": "eth", - "shortcut": "dsLINK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsLINK2x": { - "address": "0xa901e48DB5a856Da5F27E74a936259808D4C83Af", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short LINK-DAI 2x v2", - "network": "eth", - "shortcut": "dsLINK2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsLINK3x": { - "address": "0xFdB47008B909d53D4E411306d5bA5af77491e871", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short LINK-DAI 3x v2", - "network": "eth", - "shortcut": "dsLINK3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsLINK4x": { - "address": "0x937EFce07594d14f878650d5B637f022952FAe86", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short LINK-DAI 4x v2 ", - "network": "eth", - "shortcut": "dsLINK4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsREP": { - "address": "0xe33297B993c89a55806932138804B0dBB8d7cA1c", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP", - "network": "eth", - "shortcut": "dsREP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsREP2x": { - "address": "0x44262A6a07256F0711F815451F2CD1a028A0A755", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 2x", - "network": "eth", - "shortcut": "dsREP2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsREP3x": { - "address": "0xEc3de33967898c47Ec8fBb162B939C7014bD0601", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 3x", - "network": "eth", - "shortcut": "dsREP3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsREP4x": { - "address": "0x66564D3BCec69c7fbeFea185Bd6b9faA57fAEbB9", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 4x", - "network": "eth", - "shortcut": "dsREP4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsWBTC": { - "address": "0x9fC208947d92B1588F7BdE245620439568A8587a", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC", - "network": "eth", - "shortcut": "dsWBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsWBTC2x": { - "address": "0x671C7886C61A18Fc6E94893A791eaa069D70eBA7", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 2x", - "network": "eth", - "shortcut": "dsWBTC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsWBTC3x": { - "address": "0x849548F5D966017b6b49F6a3A740BBDb78176eDB", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 3x", - "network": "eth", - "shortcut": "dsWBTC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsWBTC4x": { - "address": "0x2fC9F52240F68eF0f178e1B896435D8f64A8DFaa", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 4x", - "network": "eth", - "shortcut": "dsWBTC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsZRX": { - "address": "0xDf0d727742A8A9eAcfC3305C687a0d21826daE7e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX", - "network": "eth", - "shortcut": "dsZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsZRX2x": { - "address": "0xe18E1789B96Fef7369095de1303c3acdcF03775A", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 2x", - "network": "eth", - "shortcut": "dsZRX2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsZRX3x": { - "address": "0x48786d243897C581e88b598D4F786Fb7169E08aC", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 3x", - "network": "eth", - "shortcut": "dsZRX3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:dsZRX4x": { - "address": "0xb70AE77FF9EcF13baea9807618ec7236ACf44bd1", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 4x", - "network": "eth", - "shortcut": "dsZRX4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:eBCH": { - "address": "0xaFC39788c51f0c1Ff7B55317f3e70299e521Fff6", - "links": { - "Homepage": "https://ebitcoincash.io" - }, - "marketcap_usd": 0, - "name": "eBCH", - "network": "eth", - "shortcut": "eBCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:eGAS": { - "address": "0xb53A96bcBdD9CF78dfF20BAB6C2be7bAec8f00f8", - "links": { - "Homepage": "http://www.ethgas.stream" - }, - "marketcap_usd": 0, - "name": "ETH GAS", - "network": "eth", - "shortcut": "eGAS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:eUSD": { - "address": "0x523630976eB6147621B5c31c781eBe2Ec2a806E0", - "links": { - "Github": "https://github.com/havven/havven", - "Homepage": "https://havven.io" - }, - "marketcap_usd": 0, - "name": "Ether-Backed USD Nomins (erc20)", - "network": "eth", - "shortcut": "eUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:eosDAC": { - "address": "0x7e9e431a0B8c4D532C745B1043c7FA29a48D4fBa", - "links": { - "Github": "https://github.com/eosdac", - "Homepage": "https://eosdac.io/" - }, - "marketcap_usd": 295500, - "name": "eosDAC", - "network": "eth", - "shortcut": "eosDAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:fstETHDAI": { - "address": "0xCbe83d6323a9eC795D5Cb73b333b23377a823ECC", - "links": { - "Github": "https://github.com/futureswap", - "Homepage": "https://futureswap.com" - }, - "marketcap_usd": 0, - "name": "Futureswap: ETHUSD", - "network": "eth", - "shortcut": "fstETHDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iBAT": { - "address": "0xA8b65249DE7f85494BC1fe75F525f568aa7dfa39", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx BAT iToken", - "network": "eth", - "shortcut": "iBAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iBBT": { - "address": "0x691c25C461DaFC47792b6E4d674FBB637bca1C6F", - "links": { - "Github": "https://github.com/Geopay/iBlockchain-Bank-and-Trust-Utility-Token", - "Homepage": "https://ibbt.io" - }, - "marketcap_usd": 0, - "name": "iBBT Utility Token", - "network": "eth", - "shortcut": "iBBT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iKNC": { - "address": "0x1cC9567EA2eB740824a45F8026cCF8e46973234D", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx KNC iToken", - "network": "eth", - "shortcut": "iKNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iREP": { - "address": "0xBd56E9477Fc6997609Cf45F84795eFbDAC642Ff1", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx REP iToken", - "network": "eth", - "shortcut": "iREP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iSAI": { - "address": "0x14094949152EDDBFcd073717200DA82fEd8dC960", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx SAI iToken ", - "network": "eth", - "shortcut": "iSAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iUSDC": { - "address": "0xF013406A0B1d544238083DF0B93ad0d2cBE0f65f", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx USDC iToken", - "network": "eth", - "shortcut": "iUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iWBTC": { - "address": "0xBA9262578EFef8b3aFf7F60Cd629d6CC8859C8b5", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx WBTC iToken", - "network": "eth", - "shortcut": "iWBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:iZRX": { - "address": "0xA7Eb2bc82df18013ecC2A6C533fc29446442EDEe", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx ZRX iToken", - "network": "eth", - "shortcut": "iZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:pBTC": { - "address": "0x5228a22e72ccC52d415EcFd199F99D0665E7733b", - "links": { - "Github": "https://github.com/provable-things", - "Homepage": "https://www.ptokens.io" - }, - "marketcap_usd": 0, - "name": "pTokens BTC", - "network": "eth", - "shortcut": "pBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:pUSD": { - "address": "0x93d3296cac208422BF587c3597D116e809870f2b", - "links": { - "Github": "https://github.com/pegnet", - "Homepage": "https://pegnet.org/" - }, - "marketcap_usd": 0, - "name": "PegNet pUSD", - "network": "eth", - "shortcut": "pUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLBAT2x": { - "address": "0xD199A3F8a65fD0C80A47718cB5E2D1C9f3729bC6", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 2x", - "network": "eth", - "shortcut": "uLBAT2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLBAT3x": { - "address": "0xB56f2cE679E1FfBa509EE52e9447A3dD7ABE0ba1", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 3x", - "network": "eth", - "shortcut": "uLBAT3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLBAT4x": { - "address": "0xAA2029789404A29899EC9751614eC4CcB27Ff332", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long BAT 4x", - "network": "eth", - "shortcut": "uLBAT4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLETH2x": { - "address": "0x6368b095a4F4702BF1373A0a2aD029696A2e7695", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ETH 2x", - "network": "eth", - "shortcut": "uLETH2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLETH3x": { - "address": "0x23187365195E7059FA413B33ab46a465173EB787", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ETH 3x", - "network": "eth", - "shortcut": "uLETH3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLETH4x": { - "address": "0x1287969821F9160C1aF516Af0ff18db2903386aD", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ETH 4x", - "network": "eth", - "shortcut": "uLETH4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLKNC2x": { - "address": "0xC30FA8484B1c35696c4A8cF7391ee0671592203B", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long KNC 2x", - "network": "eth", - "shortcut": "uLKNC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLKNC3x": { - "address": "0xA679aA830619768e2d8A2365526cedff7ABaC2A3", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long KNC 3x", - "network": "eth", - "shortcut": "uLKNC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLKNC4x": { - "address": "0x19197796a9D890319D86b3f8f0226400b41679fD", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long KNC 4x", - "network": "eth", - "shortcut": "uLKNC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLREP2x": { - "address": "0x187234E7a0C64dCEF6176a534ef1E9e627D9aDC8", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 2x", - "network": "eth", - "shortcut": "uLREP2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLREP3x": { - "address": "0xF4bFF845C2DD28060CDeacBD21a91cb6D2E7dd4B", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 3x", - "network": "eth", - "shortcut": "uLREP3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLREP4x": { - "address": "0x092eD67828357afC65e8aEc93d434b0217d1850A", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long REP 4x", - "network": "eth", - "shortcut": "uLREP4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLWBTC2x": { - "address": "0xbd408612BACccbF14FF26Ca0dEF859FacC3673bD", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 2x", - "network": "eth", - "shortcut": "uLWBTC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLWBTC3x": { - "address": "0x431E5f6f3368230b10B732Cef68ACFF62A9727f0", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 3x", - "network": "eth", - "shortcut": "uLWBTC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLWBTC4x": { - "address": "0x619732bE53BdFB270eE889Cf3DFe6fceE4171261", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long WBTC 4x", - "network": "eth", - "shortcut": "uLWBTC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLZRX2x": { - "address": "0x04B272A21d9a0f0aE0caE2015E9C909596b82a4d", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ZRX 2x", - "network": "eth", - "shortcut": "uLZRX2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLZRX3x": { - "address": "0xb0AE52A539E681B9d0d489FE34abA7A88f981d2e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ZRX 3x", - "network": "eth", - "shortcut": "uLZRX3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uLZRX4x": { - "address": "0x392B9FAE896594586b4e6b080916c6872e74D44F", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Long ZRX 4x", - "network": "eth", - "shortcut": "uLZRX4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uni0xBTC": { - "address": "0x701564Aa6E26816147D4fa211a0779F1B774Bb9B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: 0xBitcoin Token", - "network": "eth", - "shortcut": "uni0xBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniAMN": { - "address": "0xE6C198d27a5B71144B40cFa2362ae3166728e0C8", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Amon", - "network": "eth", - "shortcut": "uniAMN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniAMPL": { - "address": "0x042dBBDc27F75d277C3D99efE327DB21Bc4fde75", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Ampleforth", - "network": "eth", - "shortcut": "uniAMPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniANT": { - "address": "0x077d52B047735976dfdA76feF74d4d988AC25196", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Aragon Network Token", - "network": "eth", - "shortcut": "uniANT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniBAT": { - "address": "0x2E642b8D59B45a1D8c5aEf716A84FF44ea665914", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Basic Attention Token", - "network": "eth", - "shortcut": "uniBAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniBLT": { - "address": "0x0E6A53B13688018A3df8C69f99aFB19A3068D04f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Bloom Token", - "network": "eth", - "shortcut": "uniBLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniBNT": { - "address": "0x87d80DBD37E551F58680B4217b23aF6a752DA83F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Bancor Network Token", - "network": "eth", - "shortcut": "uniBNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniC20": { - "address": "0xF7B5A4b934658025390ff69dB302BC7F2AC4a542", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Crypto20", - "network": "eth", - "shortcut": "uniC20", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniCELR": { - "address": "0x1e3740A030AF8c755c888a0ee83aC9E79e09f4F1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: CelerToken", - "network": "eth", - "shortcut": "uniCELR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniCHAI": { - "address": "0x6C3942B383bc3d0efd3F36eFa1CBE7C8E12C8A2B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Chai", - "network": "eth", - "shortcut": "uniCHAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniCVC": { - "address": "0x1C6c712b1F4a7c263B1DBd8F97fb447c945d3b9a", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Civic", - "network": "eth", - "shortcut": "uniCVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDAI": { - "address": "0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Dai Stablecoin", - "network": "eth", - "shortcut": "uniDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDATA": { - "address": "0x4F0d6E2179938828CfF93dA40a8BA1Df7519Ca8C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Streamr DATAcoin", - "network": "eth", - "shortcut": "uniDATA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDGD": { - "address": "0xD55C1cA9F5992A2e5E379DCe49Abf24294ABe055", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: DigixDAO", - "network": "eth", - "shortcut": "uniDGD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDGX": { - "address": "0xb92dE8B30584392Af27726D5ce04Ef3c4e5c9924", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Digix Gold Token", - "network": "eth", - "shortcut": "uniDGX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDIP": { - "address": "0x61792F290e5100FBBcBb2309F03A1Bab869fb850", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Decentralized Insurance Protocol", - "network": "eth", - "shortcut": "uniDIP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniDONUT": { - "address": "0xD552119eD44EC8Fa8f87c568769C67Bd02B5b3FB", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Donut", - "network": "eth", - "shortcut": "uniDONUT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniENJ": { - "address": "0xb99A23b1a4585fc56d0EC3B76528C27cAd427473", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Enjin Coin", - "network": "eth", - "shortcut": "uniENJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniFAME": { - "address": "0x5e7907aC70b9a781365c72F2acEE96710bdA042e", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: SAINT FAME: Genesis Shirt", - "network": "eth", - "shortcut": "uniFAME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniFOAM": { - "address": "0xf79cb3BEA83BD502737586A6E8B133c378FD1fF2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: FOAM Token", - "network": "eth", - "shortcut": "uniFOAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniFUN": { - "address": "0x60a87cC7Fca7E53867facB79DA73181B1bB4238B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: FunFair", - "network": "eth", - "shortcut": "uniFUN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniGEN": { - "address": "0x26Cc0EAb6Cb650B0Db4D0d0dA8cB5BF69F4ad692", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: DAOstack", - "network": "eth", - "shortcut": "uniGEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniGNO": { - "address": "0xe8e45431b93215566BA923a7E611B7342Ea954DF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Gnosis Token", - "network": "eth", - "shortcut": "uniGNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniGRID": { - "address": "0x4B17685b330307C751B47f33890c8398dF4Fe407", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: GRID Token", - "network": "eth", - "shortcut": "uniGRID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniGST2": { - "address": "0x929507CD3D90Ab11eC4822E9eB5A48eb3a178F19", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Gastoken.io", - "network": "eth", - "shortcut": "uniGST2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniHOT": { - "address": "0xd4777E164c6C683E10593E08760B803D58529a8E", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: HoloToken", - "network": "eth", - "shortcut": "uniHOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniIOTX": { - "address": "0x084f002671a5f03D5498B1e5fb15fc0cfee9a470", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: IoTeX Network", - "network": "eth", - "shortcut": "uniIOTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniKIN": { - "address": "0xb7520a5F8c832c573d6BD0Df955fC5c9b72400F7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Kin", - "network": "eth", - "shortcut": "uniKIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniKNC": { - "address": "0x49c4f9bc14884f6210F28342ceD592A633801a8b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Kyber Network Crystal", - "network": "eth", - "shortcut": "uniKNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLEND": { - "address": "0xcaA7e4656f6A2B59f5f99c745F91AB26D1210DCe", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: EthLend Token", - "network": "eth", - "shortcut": "uniLEND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLINK": { - "address": "0xF173214C720f58E03e194085B1DB28B50aCDeeaD", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: ChainLink Token", - "network": "eth", - "shortcut": "uniLINK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLOOM": { - "address": "0x417CB32bc991fBbDCaE230C7c4771CC0D69daA6b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: LoomToken", - "network": "eth", - "shortcut": "uniLOOM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLPT": { - "address": "0xc4a1C45D5546029Fd57128483aE65b56124BFA6A", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Livepeer Token", - "network": "eth", - "shortcut": "uniLPT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLQD": { - "address": "0xe3406e7D0155E0a83236eC25D34Cd3D903036669", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Liquidity.Network Token", - "network": "eth", - "shortcut": "uniLQD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniLRC": { - "address": "0xA539BAaa3aCA455c986bB1E25301CEF936CE1B65", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: LoopringCoin V2", - "network": "eth", - "shortcut": "uniLRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMANA": { - "address": "0xC6581Ce3A005e2801c1e0903281BBd318eC5B5C2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Decentraland MANA", - "network": "eth", - "shortcut": "uniMANA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMATIC": { - "address": "0x9a7A75E66B325a3BD46973B2b57c9b8d9D26a621", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Matic Token", - "network": "eth", - "shortcut": "uniMATIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMBC": { - "address": "0xE1b7AeC3639068b474bFbcB916580fc28A20717B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Marblecoin", - "network": "eth", - "shortcut": "uniMBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMGN": { - "address": "0xdd80Ca8062c7Ef90FcA2547E6a2A126C596e611F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Magnolia Token", - "network": "eth", - "shortcut": "uniMGN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMKR": { - "address": "0x2C4Bd064b998838076fa341A83d007FC2FA50957", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Maker", - "network": "eth", - "shortcut": "uniMKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMLN": { - "address": "0xA931F4eB165AC307fD7431b5EC6eADde53E14b0C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Melon Token", - "network": "eth", - "shortcut": "uniMLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniMOD": { - "address": "0xCCB98654CD486216fFF273dd025246588E77cFC1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Modum Token", - "network": "eth", - "shortcut": "uniMOD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniNEXO": { - "address": "0x069C97DBA948175D10af4b2414969e0B88d44669", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Nexo", - "network": "eth", - "shortcut": "uniNEXO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniNMR": { - "address": "0x2Bf5A5bA29E60682fC56B2Fcf9cE07Bef4F6196f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Numeraire", - "network": "eth", - "shortcut": "uniNMR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniOXT": { - "address": "0xe9a5bbe41dc63D555E06746b047d624E3343EA52", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Orchid", - "network": "eth", - "shortcut": "uniOXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniPAN": { - "address": "0xF53bBFBff01c50F2D42D542b09637DcA97935fF7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Panvala pan", - "network": "eth", - "shortcut": "uniPAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniPAX": { - "address": "0xC040d51b07Aea5d94a89Bc21E8078B77366Fc6C7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: PAX", - "network": "eth", - "shortcut": "uniPAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniPAXG": { - "address": "0x0d2E1a84638bD1B6c0C260c758c39451D4587be1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Paxos Gold", - "network": "eth", - "shortcut": "uniPAXG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniPNK": { - "address": "0xF506828B166de88cA2EDb2A98D960aBba0D2402A", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Pinakion", - "network": "eth", - "shortcut": "uniPNK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniPOA20": { - "address": "0xA2E6B3EF205FeAEe475937c4883b24E6eB717eeF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: POA ERC20 on Foundation", - "network": "eth", - "shortcut": "uniPOA20", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniQCH": { - "address": "0x755899F0540c3548b99E68C59AdB0f15d2695188", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: QChi", - "network": "eth", - "shortcut": "uniQCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniQSP": { - "address": "0x82Db9FC4956Fa40efe1e35d881004612B5CB2cc2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Quantstamp Token", - "network": "eth", - "shortcut": "uniQSP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniRCN": { - "address": "0xD91FF16Ef92568fC27F466C3c5613e43313Ab1dc", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Ripio Credit Network Token", - "network": "eth", - "shortcut": "uniRCN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniRDN": { - "address": "0x7D03CeCb36820b4666F45E1b4cA2538724Db271C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Raiden Token", - "network": "eth", - "shortcut": "uniRDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniREN": { - "address": "0x43892992B0b102459E895B88601Bb2C76736942c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Republic Token", - "network": "eth", - "shortcut": "uniREN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniREP": { - "address": "0x48B04d2A05B6B604d8d5223Fd1984f191DED51af", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Reputation", - "network": "eth", - "shortcut": "uniREP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniRING": { - "address": "0xeBD8AA50b26bFa63007d61eBa777A9DdE7e43c64", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Darwinia Network Native Token", - "network": "eth", - "shortcut": "uniRING", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniRLC": { - "address": "0xA825CAE02B310E9901b4776806CE25db520c8642", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: iEx.ec Network Token", - "network": "eth", - "shortcut": "uniRLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniRPL": { - "address": "0x3Fb2F18065926DdB33E7571475c509541d15dA0e", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Rocket Pool", - "network": "eth", - "shortcut": "uniRPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSAI": { - "address": "0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Dai Stablecoin v1.0 (SAI)", - "network": "eth", - "shortcut": "uniSAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSALT": { - "address": "0xC0C59cDe851bfcbdddD3377EC10ea54A18Efb937", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Salt", - "network": "eth", - "shortcut": "uniSALT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSAN": { - "address": "0x8a8D7aD4b89D91983cd069C58C4AA9F2f4166298", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: SANtiment network token", - "network": "eth", - "shortcut": "uniSAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSHUF": { - "address": "0x536956Fab86774fb55CfaAcF496BC25E4d2B435C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Shuffle.Monster V3", - "network": "eth", - "shortcut": "uniSHUF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSNT": { - "address": "0x1aEC8F11A7E78dC22477e91Ed924Fab46e3A88Fd", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Status Network Token", - "network": "eth", - "shortcut": "uniSNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSNX": { - "address": "0x3958B4eC427F8fa24eB60F42821760e88d485f7F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Synthetix Network Token", - "network": "eth", - "shortcut": "uniSNX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSOCKS": { - "address": "0x22d8432cc7aA4f8712a655fC4cdfB1baEC29FCA9", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Unisocks Edition 0", - "network": "eth", - "shortcut": "uniSOCKS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSPANK": { - "address": "0x4e395304655F0796bc3bc63709DB72173b9DdF98", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: SPANK", - "network": "eth", - "shortcut": "uniSPANK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniSTORJ": { - "address": "0xA7298541E52f96d42382eCBe4f242cBcBC534d02", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: StorjToken", - "network": "eth", - "shortcut": "uniSTORJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTAUD": { - "address": "0x88dF13889E20EFa93Ff9a0C08f101F431bD9DDD7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: TrueAUD", - "network": "eth", - "shortcut": "uniTAUD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTCAD": { - "address": "0xF996D7d9BaCb9217ca64BBce1b1cD72E0E886Be6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: TrueCAD", - "network": "eth", - "shortcut": "uniTCAD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTGBP": { - "address": "0x6bFa119a191576Ba26Bc5e711432aCA0cFda04DE", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: TrueGBP", - "network": "eth", - "shortcut": "uniTGBP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTHKD": { - "address": "0x505C02B4aa1286375FBDF0c390AC0fe9209DCB05", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: TrueHKD", - "network": "eth", - "shortcut": "uniTHKD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTKN": { - "address": "0xb6cFBf322db47D39331E306005DC7E5e6549942B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Monolith TKN", - "network": "eth", - "shortcut": "uniTKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTRST": { - "address": "0x95E4649F5209dD292cAF1F087b8F1Db3bE24927f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Trustcoin", - "network": "eth", - "shortcut": "uniTRST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTRYB": { - "address": "0x122327Fd43B2C66DD9e4B6c91c8f071E217558eF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: BiLira", - "network": "eth", - "shortcut": "uniTRYB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniTUSD": { - "address": "0x5048b9d01097498Fd72F3F14bC9Bc74A5aAc8fA7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: TrueUSD", - "network": "eth", - "shortcut": "uniTUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniUNI-V1:SAI": { - "address": "0x601c32E0580D3aef9437dB52D09f5a5D7E60eC22", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Uniswap V1", - "network": "eth", - "shortcut": "uniUNI-V1:SAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniUSDC": { - "address": "0x97deC872013f6B5fB443861090ad931542878126", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: USD//C", - "network": "eth", - "shortcut": "uniUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniUSDS": { - "address": "0x7Ef7191AB91dDB4D7cC347fbFA170355acbaf02D", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: StableUSD", - "network": "eth", - "shortcut": "uniUSDS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniVERI": { - "address": "0x17e5BF07D696eaf0d14caA4B44ff8A1E17B34de3", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Veritaseum", - "network": "eth", - "shortcut": "uniVERI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniWBTC": { - "address": "0x4d2f5cFbA55AE412221182D8475bC85799A5644b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Wrapped BTC", - "network": "eth", - "shortcut": "uniWBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniWCK": { - "address": "0x4FF7Fa493559c40aBd6D157a0bfC35Df68d8D0aC", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Wrapped CryptoKitties", - "network": "eth", - "shortcut": "uniWCK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniWETH": { - "address": "0xA2881A90Bf33F03E7a3f803765Cd2ED5c8928dFb", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Wrapped Ether", - "network": "eth", - "shortcut": "uniWETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniXCHF": { - "address": "0x8dE0d002DC83478f479dC31F76cB0a8aa7CcEa17", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: CryptoFranc", - "network": "eth", - "shortcut": "uniXCHF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniXIO": { - "address": "0x7B6E5278a14d5318571d65aceD036d09c998C707", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: XIO Network", - "network": "eth", - "shortcut": "uniXIO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniZRX": { - "address": "0xaE76c84C9262Cdb9abc0C2c8888e62Db8E22A0bF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: 0x Protocol Token", - "network": "eth", - "shortcut": "uniZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniaDAI": { - "address": "0x7cfab87AaC0899c093235b342AC0e5B1ACF159EB", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Aave Interest bearing DAI", - "network": "eth", - "shortcut": "uniaDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:unicDAI": { - "address": "0x34E89740adF97C3A9D3f63Cc2cE4a914382c230b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Compound Dai", - "network": "eth", - "shortcut": "unicDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:unicSAI": { - "address": "0x45A2FDfED7F7a2c791fb1bdF6075b83faD821ddE", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Compound Dai", - "network": "eth", - "shortcut": "unicSAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniiDAI": { - "address": "0x3E0349F5D38414008B9Bb1907ea422739BE7CD4C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Fulcrum DAI iToken ", - "network": "eth", - "shortcut": "uniiDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniiSAI": { - "address": "0x81eeD7F1EcbD7FA9978fcc7584296Fb0C215Dc5C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Fulcrum SAI iToken ", - "network": "eth", - "shortcut": "uniiSAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:uniimBTC": { - "address": "0xFFcf45b540e6C9F094Ae656D2e34aD11cdfdb187", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: The Tokenized Bitcoin", - "network": "eth", - "shortcut": "uniimBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:unisETH": { - "address": "0xe9Cf7887b93150D4F2Da7dFc6D502B216438F244", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Synth sETH", - "network": "eth", - "shortcut": "unisETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:unisUSD": { - "address": "0xB944d13b2f4047fc7bd3F7013bcf01b115fb260d", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.io" - }, - "marketcap_usd": 0, - "name": "Uniswap: Synth sUSD", - "network": "eth", - "shortcut": "unisUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ20xBTCETH": { - "address": "0xc12c4c3E0008B838F75189BFb39283467cf6e5b3", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 0xBTC-ETH", - "network": "eth", - "shortcut": "univ20xBTCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ21UPETH": { - "address": "0xF49144E61C05120f1b167E4B4F59cf0a5d77903F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 1UP-ETH", - "network": "eth", - "shortcut": "univ21UPETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2AKROETH": { - "address": "0x8Cb77eA869DeF8f7fdEab9E4dA6cF02897bbF076", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 AKRO-ETH", - "network": "eth", - "shortcut": "univ2AKROETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ALEPHETH": { - "address": "0x583CaDD830374bb5C1eC8E1b648e0294CC1E01f1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ALEPH-ETH", - "network": "eth", - "shortcut": "univ2ALEPHETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ATISETH": { - "address": "0x490B5B2489eeFC4106C69743F657e3c4A2870aC5", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ATIS-ETH", - "network": "eth", - "shortcut": "univ2ATISETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BANDETH": { - "address": "0xf421c3f2e695C2D4C0765379cCace8adE4a480D9", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BAND-ETH", - "network": "eth", - "shortcut": "univ2BANDETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BATETH": { - "address": "0xB6909B960DbbE7392D405429eB2b3649752b4838", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BAT-ETH", - "network": "eth", - "shortcut": "univ2BATETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BIZETH": { - "address": "0xFAD8B07055A0371442A3106A2244a82B24e31cEc", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BIZ-ETH", - "network": "eth", - "shortcut": "univ2BIZETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BNTETH": { - "address": "0x3fd4Cf9303c4BC9E13772618828712C8EaC7Dd2F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BNT-ETH", - "network": "eth", - "shortcut": "univ2BNTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BOOSTETH": { - "address": "0x6B4A0Bd2EEe3Ca06652f758844937dAF91eA8422", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BOOST-ETH", - "network": "eth", - "shortcut": "univ2BOOSTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2BPTETH": { - "address": "0x13E638b4f89740a1c2FF45D71F71ee28101CC1Dc", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 BPT-ETH", - "network": "eth", - "shortcut": "univ2BPTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2CAMOETH": { - "address": "0x48F4A6C65ABb4b209823771b0D2c0F156eE6268b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 CAMO-ETH", - "network": "eth", - "shortcut": "univ2CAMOETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2CELETH": { - "address": "0xa5E79baEe540f000ef6F23D067cd3AC22c7d9Fe6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 CEL-ETH", - "network": "eth", - "shortcut": "univ2CELETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2CHIETH": { - "address": "0xa6f3ef841d371a82ca757FaD08efc0DeE2F1f5e2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 CHI-ETH", - "network": "eth", - "shortcut": "univ2CHIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2COMPETH": { - "address": "0xCFfDdeD873554F362Ac02f8Fb1f02E5ada10516f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 COMP-ETH", - "network": "eth", - "shortcut": "univ2COMPETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2CREAMETH": { - "address": "0xddF9b7a31b32EBAF5c064C80900046C9e5b7C65F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 CREAM-ETH", - "network": "eth", - "shortcut": "univ2CREAMETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAI2KEY": { - "address": "0xda9A09ed40015346f6B0704c5Bf1A2ccbF94dE43", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-2KEY", - "network": "eth", - "shortcut": "univ2DAI2KEY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAIALEPH": { - "address": "0x18e33723feF43A33f9560a8B973D3331E5269FAC", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-ALEPH", - "network": "eth", - "shortcut": "univ2DAIALEPH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAIETH": { - "address": "0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-ETH", - "network": "eth", - "shortcut": "univ2DAIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAIJRT": { - "address": "0xE4a356Afd925F73F3DD22ACbEb2c0C87A05E895D", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-JRT", - "network": "eth", - "shortcut": "univ2DAIJRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAILEND": { - "address": "0xb603c2b5AB4ee7932103b42f8dd899C8721DD25E", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-LEND", - "network": "eth", - "shortcut": "univ2DAILEND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAIMFT": { - "address": "0xe8056B83ba7dAF027414b58048a48911acf1b2A9", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-MFT", - "network": "eth", - "shortcut": "univ2DAIMFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DAIUSDC": { - "address": "0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DAI-USDC", - "network": "eth", - "shortcut": "univ2DAIUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DATAETH": { - "address": "0xD6054455Ca2e1AEf02178E0462D9ab953bEA4e23", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DATA-ETH", - "network": "eth", - "shortcut": "univ2DATAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DECETH": { - "address": "0x3AEEE5bA053eF8406420DbC5801fC95eC57b0E0A", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DEC-ETH", - "network": "eth", - "shortcut": "univ2DECETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DEVETH": { - "address": "0x4168CEF0fCa0774176632d86bA26553E3B9cF59d", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DEV-ETH", - "network": "eth", - "shortcut": "univ2DEVETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DEXTETH": { - "address": "0x37a0464f8F4c207B54821f3C799Afd3D262Aa944", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DEXT-ETH", - "network": "eth", - "shortcut": "univ2DEXTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DXDETH": { - "address": "0x1c9052e823b5f4611EF7D5fB4153995b040ccbf5", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DXD-ETH", - "network": "eth", - "shortcut": "univ2DXDETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2DZARETH": { - "address": "0xC5A788F63e5D9cF2C324621EEd51A98F85AE373b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 DZAR-ETH", - "network": "eth", - "shortcut": "univ2DZARETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2EBASEETH": { - "address": "0x3b0F0fe3Be830826D833a67cD1d7C80edF3Fb49b", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 EBASE-ETH", - "network": "eth", - "shortcut": "univ2EBASEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ESWAETH": { - "address": "0x8C0e876F1da58140695673D07FF42D4786207D1B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ESWA-ETH", - "network": "eth", - "shortcut": "univ2ESWAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETH2KEY": { - "address": "0x63E7Aa05B78144013Cfa4b23C9b61599D0a29023", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-2KEY", - "network": "eth", - "shortcut": "univ2ETH2KEY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHACID": { - "address": "0xA0d06BdC3274564ddda65BFAb6AE61e5f000E49B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ACID", - "network": "eth", - "shortcut": "univ2ETHACID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHAMPL": { - "address": "0xc5be99A02C6857f9Eac67BbCE58DF5572498F40c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-AMPL", - "network": "eth", - "shortcut": "univ2ETHAMPL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHANJ": { - "address": "0x0FFC70bE6e2d841e109653ddb3034961591679d6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ANJ", - "network": "eth", - "shortcut": "univ2ETHANJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHASKO": { - "address": "0x63804D757B5B7c43509FDED8f7CE10Cc0Bac2AE0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ASKO", - "network": "eth", - "shortcut": "univ2ETHASKO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHAUC": { - "address": "0xC04744ab87A4C37afD91680ef280B96Ee21A026E", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-AUC", - "network": "eth", - "shortcut": "univ2ETHAUC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHBUIDL": { - "address": "0x8A38aD17d1adCDBE3775338D1470FD6f00f77802", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-BUIDL", - "network": "eth", - "shortcut": "univ2ETHBUIDL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHCKN": { - "address": "0x938d1459ee0aaf8fE73778c590A639821E444D45", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-CKN", - "network": "eth", - "shortcut": "univ2ETHCKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHDAM": { - "address": "0x447f8D287120B66F39856AE5ceb01512A7A47444", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-DAM", - "network": "eth", - "shortcut": "univ2ETHDAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHDAOX": { - "address": "0x0782Fb026d1c264e59A2b274833240c53367Ed1A", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-DAOX", - "network": "eth", - "shortcut": "univ2ETHDAOX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHDMG": { - "address": "0x8175362afBeeE32AfB22d05adc0bbD08dE32F5Ae", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-DMG", - "network": "eth", - "shortcut": "univ2ETHDMG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHENJ": { - "address": "0xE56c60B5f9f7B5FC70DE0eb79c6EE7d00eFa2625", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ENJ", - "network": "eth", - "shortcut": "univ2ETHENJ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHESH": { - "address": "0x121B382b5F003C41fb49E7B88D079c8f513fEaaC", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ESH", - "network": "eth", - "shortcut": "univ2ETHESH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHFRM": { - "address": "0x92330D8818e8A3B50f027C819FA46031FfBa2C8C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-FRM", - "network": "eth", - "shortcut": "univ2ETHFRM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHFSW": { - "address": "0xE275eB6154cB4A73F0BA573E43b2b06E9E78b7f0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-FSW", - "network": "eth", - "shortcut": "univ2ETHFSW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHHEX2T": { - "address": "0xedAeDD22e653c504ff6806bf61664292848eB26e", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-HEX2T", - "network": "eth", - "shortcut": "univ2ETHHEX2T", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHKNC": { - "address": "0xf49C43Ae0fAf37217bDcB00DF478cF793eDd6687", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-KNC", - "network": "eth", - "shortcut": "univ2ETHKNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHNEC": { - "address": "0x2dda09fB929c576A6AB6c1D1EE62E8AF72b2F6a7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-NEC", - "network": "eth", - "shortcut": "univ2ETHNEC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHPAMP": { - "address": "0x1C608235E6A946403F2a048a38550BefE41e1B85", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-PAMP", - "network": "eth", - "shortcut": "univ2ETHPAMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHPAN": { - "address": "0x1b21609D42fa32F371F58DF294eD25b2D2e5C8ba", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-PAN", - "network": "eth", - "shortcut": "univ2ETHPAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHPDS": { - "address": "0x2EcF245B60e351A711e56A3ae25866d1c8BEb324", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-PDS", - "network": "eth", - "shortcut": "univ2ETHPDS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHPOWER": { - "address": "0x49F9316EB22de90d9343C573fbD7Cc0B5ec6e19f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-POWER", - "network": "eth", - "shortcut": "univ2ETHPOWER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHSHIP": { - "address": "0xfb7A3112c96Bbcfe4bbf3e8627b0dE6f49E5142A", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-SHIP", - "network": "eth", - "shortcut": "univ2ETHSHIP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHSWAP": { - "address": "0xD90a1ba0cbaaaabfdC6C814cDF1611306A26E1f8", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-SWAP", - "network": "eth", - "shortcut": "univ2ETHSWAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHUBOMB": { - "address": "0xEd9C854Cb02dE75Ce4C9BBA992828d6CB7fd5C71", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-UBOMB", - "network": "eth", - "shortcut": "univ2ETHUBOMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHUNC": { - "address": "0x5E64CD6f84D0eE2Ad2a84CadC464184e36274E0c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-UNC", - "network": "eth", - "shortcut": "univ2ETHUNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHUSDT": { - "address": "0x0d4a11d5EEaaC28EC3F61d100daF4d40471f1852", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-USDT", - "network": "eth", - "shortcut": "univ2ETHUSDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHXAMP": { - "address": "0x6c35c40447E8011a63aB05f088fa7cD914d66904", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-XAMP", - "network": "eth", - "shortcut": "univ2ETHXAMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2ETHZRX": { - "address": "0xc6F348dd3B91a56D117ec0071C1e9b83C0996De4", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 ETH-ZRX", - "network": "eth", - "shortcut": "univ2ETHZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2EWTBETH": { - "address": "0xdc7d8cC3a22FE0eC69770E02931f43451b7B975e", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 EWTB-ETH", - "network": "eth", - "shortcut": "univ2EWTBETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2FMAETH": { - "address": "0x9926285361ACf7461105B464Ae9EA683DFB06b83", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 FMA-ETH", - "network": "eth", - "shortcut": "univ2FMAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2FOAMETH": { - "address": "0xd9d39540d61F8D6Eb2EE7eEdFae93CC09cC24f0E", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 FOAM-ETH", - "network": "eth", - "shortcut": "univ2FOAMETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2FUNETH": { - "address": "0x05B0c1D8839eF3a989B33B6b63D3aA96cB7Ec142", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 FUN-ETH", - "network": "eth", - "shortcut": "univ2FUNETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2FXCETH": { - "address": "0x302Ac87B1b5ef18485971ED0115a17403Ea30911", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 FXC-ETH", - "network": "eth", - "shortcut": "univ2FXCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2GENETH": { - "address": "0xf37Ed742819Ec006b0802df5c2B0e9132F22C625", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 GEN-ETH", - "network": "eth", - "shortcut": "univ2GENETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2GHOSTETH": { - "address": "0x395A1350db9627360D09c8b3E7C31FB84261B8F2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 GHOST-ETH", - "network": "eth", - "shortcut": "univ2GHOSTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2GHSTETH": { - "address": "0xaB659deE3030602c1aF8C29D146fAcD4aeD6EC85", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 GHST-ETH", - "network": "eth", - "shortcut": "univ2GHSTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2H3XETH": { - "address": "0x308E019143B560215775A0c6EFbD2673413D76E6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 H3X-ETH", - "network": "eth", - "shortcut": "univ2H3XETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2HEXETH": { - "address": "0x55D5c232D921B9eAA6b37b5845E439aCD04b4DBa", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 HEX-ETH", - "network": "eth", - "shortcut": "univ2HEXETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2HKMTUSDT": { - "address": "0xF52f433B79d21023af94251958BEd3b64a2b7930", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 HKMT-USDT", - "network": "eth", - "shortcut": "univ2HKMTUSDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2HXBETH": { - "address": "0xaDEA645907Dbe2b9BCB7B102695Ad0C321f6b40c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 HXB-ETH", - "network": "eth", - "shortcut": "univ2HXBETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2IDXTETH": { - "address": "0xFdC3f68Af20d56e05AD0C7Eb51DA4A3F7D753a04", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 IDXT-ETH", - "network": "eth", - "shortcut": "univ2IDXTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2JRTETH": { - "address": "0x2b6A25f7C54F43C71C743e627F5663232586C39F", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 JRT-ETH", - "network": "eth", - "shortcut": "univ2JRTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2KAIETH": { - "address": "0x6507ba0f3eb82cba185c088A3fBD0435f1A73B28", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 KAI-ETH", - "network": "eth", - "shortcut": "univ2KAIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LENDETH": { - "address": "0xaB3F9bF1D81ddb224a2014e98B238638824bCf20", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LEND-ETH", - "network": "eth", - "shortcut": "univ2LENDETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LENDUSDC": { - "address": "0x308d87865397672a74Ec62B3dC8E7323a18c0f1e", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LEND-USDC", - "network": "eth", - "shortcut": "univ2LENDUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LINKETH": { - "address": "0xa2107FA5B38d9bbd2C461D6EDf11B11A50F6b974", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LINK-ETH", - "network": "eth", - "shortcut": "univ2LINKETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LPTDAI": { - "address": "0xdDb5049FDb73Ea84429Cd91f31d90779032e5eDE", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LPT-DAI", - "network": "eth", - "shortcut": "univ2LPTDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LPTETH": { - "address": "0x755C1a8F71f4210CD7B60b9439451EfCbeBa33D1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LPT-ETH", - "network": "eth", - "shortcut": "univ2LPTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2LRCETH": { - "address": "0x8878Df9E1A7c87dcBf6d3999D997f262C05D8C70", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 LRC-ETH", - "network": "eth", - "shortcut": "univ2LRCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MANAETH": { - "address": "0x11b1f53204d03E5529F09EB3091939e4Fd8c9CF3", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MANA-ETH", - "network": "eth", - "shortcut": "univ2MANAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MATHETH": { - "address": "0x3006c0D2A6e54d3590a44384c6F066c9cF9a4ceA", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MATH-ETH", - "network": "eth", - "shortcut": "univ2MATHETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MCBETH": { - "address": "0x10cfa744c77F1cB9A77fa418ac4a1B6ec62BcCE4", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MCB-ETH", - "network": "eth", - "shortcut": "univ2MCBETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MEMEETH": { - "address": "0x5DFbe95925FFeb68f7d17920Be7b313289a1a583", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MEME-ETH", - "network": "eth", - "shortcut": "univ2MEMEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MKRETH": { - "address": "0xC2aDdA861F89bBB333c90c492cB837741916A225", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MKR-ETH", - "network": "eth", - "shortcut": "univ2MKRETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MKRMLN": { - "address": "0xadea7c5febF93a6239E73e14e37aB429039Eb9B1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MKR-MLN", - "network": "eth", - "shortcut": "univ2MKRMLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MKRUSDC": { - "address": "0x340A5a2F73eBaa181eC2826802Fdf8ED21Fc759a", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MKR-USDC", - "network": "eth", - "shortcut": "univ2MKRUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MOONETH": { - "address": "0xf89403ad67d659d5d1FAe7c6Ec163110506b858a", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MOON-ETH", - "network": "eth", - "shortcut": "univ2MOONETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2MRDNETH": { - "address": "0xAacd36c877408824EE59540B0C093804D7e9a7d9", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 MRDN-ETH", - "network": "eth", - "shortcut": "univ2MRDNETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2NMRETH": { - "address": "0xB784CED6994c928170B417BBd052A096c6fB17E2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 NMR-ETH", - "network": "eth", - "shortcut": "univ2NMRETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2OCEANETH": { - "address": "0x9b7DaD79FC16106b47a3DAb791F389C167e15Eb0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 OCEAN-ETH", - "network": "eth", - "shortcut": "univ2OCEANETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2OGNETH": { - "address": "0xce2Cc0513634CEf3a7C9C257E294EF5E3092f185", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 OGN-ETH", - "network": "eth", - "shortcut": "univ2OGNETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2PAXGETH": { - "address": "0x9C4Fe5FFD9A9fC5678cFBd93Aa2D4FD684b67C4C", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 PAXG-ETH", - "network": "eth", - "shortcut": "univ2PAXGETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2PICKLEETH": { - "address": "0xdc98556Ce24f007A5eF6dC1CE96322d65832A819", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 PICKLE-ETH", - "network": "eth", - "shortcut": "univ2PICKLEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2PLRETH": { - "address": "0xaE2D4004241254aEd3f93873604d39883c8259F0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 PLR-ETH", - "network": "eth", - "shortcut": "univ2PLRETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2PNKETH": { - "address": "0x343FD171caf4F0287aE6b87D75A8964Dc44516Ab", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 PNK-ETH", - "network": "eth", - "shortcut": "univ2PNKETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2PODETH": { - "address": "0xe7cca784b1D838D99Ff4ffF574D31870d1619C1d", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 POD-ETH", - "network": "eth", - "shortcut": "univ2PODETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RAINETH": { - "address": "0xcB7f78A079B5fC387C80b93BE79d40309C27A237", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 RAIN-ETH", - "network": "eth", - "shortcut": "univ2RAINETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RELETH": { - "address": "0x33be7eD806479061A7E62A33D3C9B500fc9B47BF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 REL-ETH", - "network": "eth", - "shortcut": "univ2RELETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RENETH": { - "address": "0x8Bd1661Da98EBDd3BD080F0bE4e6d9bE8cE9858c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 REN-ETH", - "network": "eth", - "shortcut": "univ2RENETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2REPETH": { - "address": "0xec2D2240D02A8cf63C3fA0B7d2C5a3169a319496", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 REP-ETH", - "network": "eth", - "shortcut": "univ2REPETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RINGETH": { - "address": "0xa32523371390b0Cc4e11F6Bb236ecf4C2cDEA101", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 RING-ETH", - "network": "eth", - "shortcut": "univ2RINGETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RLCETH": { - "address": "0x6d57a53A45343187905aaD6AD8eD532D105697c1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 RLC-ETH", - "network": "eth", - "shortcut": "univ2RLCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RPLETH": { - "address": "0x70EA56e46266f0137BAc6B75710e3546f47C855D", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 RPL-ETH", - "network": "eth", - "shortcut": "univ2RPLETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2RSRETH": { - "address": "0xba65016890709dBC9491Ca7bF5DE395B8441DC8B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 RSR-ETH", - "network": "eth", - "shortcut": "univ2RSRETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2SAKEETH": { - "address": "0xd2E0C4928789e5DB620e53af29F5fC7bcA262635", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 SAKE-ETH", - "network": "eth", - "shortcut": "univ2SAKEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2SHUFETH": { - "address": "0x260E069deAd76baAC587B5141bB606Ef8b9Bab6c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 SHUF-ETH", - "network": "eth", - "shortcut": "univ2SHUFETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2SNXETH": { - "address": "0x43AE24960e5534731Fc831386c07755A2dc33D47", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 SNX-ETH", - "network": "eth", - "shortcut": "univ2SNXETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2STAETH": { - "address": "0x59F96b8571E3B11f859A09Eaf5a790A138FC64D0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 STA-ETH", - "network": "eth", - "shortcut": "univ2STAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2STAKEETH": { - "address": "0x3B3d4EeFDc603b232907a7f3d0Ed1Eea5C62b5f7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 STAKE-ETH", - "network": "eth", - "shortcut": "univ2STAKEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2STONKETH": { - "address": "0xe0A08fD1366b5B4CF256dB1a85B6eb0E01AAcbCE", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 STONK-ETH", - "network": "eth", - "shortcut": "univ2STONKETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2STORJETH": { - "address": "0xAEF16913b6C50EBCf627a394921F306985FC8604", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 STORJ-ETH", - "network": "eth", - "shortcut": "univ2STORJETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2SoETHETH": { - "address": "0xEAf1Cc33b8D1C4C3E67CF647E1173f06Aa7B6d0c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 SoETH-ETH", - "network": "eth", - "shortcut": "univ2SoETHETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2TRACETH": { - "address": "0x1A58Aa618DF8F1eC282748feF6185C1a1cC2FAa6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 TRAC-ETH", - "network": "eth", - "shortcut": "univ2TRACETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2TRADEETH": { - "address": "0xB8172076ceb35B6701F96eB9088818EFc010BD44", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 TRADE-ETH", - "network": "eth", - "shortcut": "univ2TRADEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2TRBDAI": { - "address": "0x27eF0CB021446f6d43aDF0Bcc74b64fd9c0AB180", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 TRB-DAI", - "network": "eth", - "shortcut": "univ2TRBDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2TRBETH": { - "address": "0x70258Aa9830C2C84d855Df1D61E12C256F6448b4", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 TRB-ETH", - "network": "eth", - "shortcut": "univ2TRBETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2UBTETH": { - "address": "0xB27dE0bA2abFbFdf15667a939f041b52118aF5Ba", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 UBT-ETH", - "network": "eth", - "shortcut": "univ2UBTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2UMAETH": { - "address": "0x88D97d199b9ED37C29D846d00D443De980832a22", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 UMA-ETH", - "network": "eth", - "shortcut": "univ2UMAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2UNIETH": { - "address": "0xd3d2E2692501A5c9Ca623199D38826e513033a17", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 UNI-ETH", - "network": "eth", - "shortcut": "univ2UNIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2UNIUSDETH": { - "address": "0xBD39b1F24B8960d3d7Cd2c5471d0493496888185", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 UNIUSD-ETH", - "network": "eth", - "shortcut": "univ2UNIUSDETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2USDCBUIDL": { - "address": "0xfd226C17A57f5eEF0b848D9b65bc53Cbbf7eD965", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 USDC-BUIDL", - "network": "eth", - "shortcut": "univ2USDCBUIDL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2USDCETH": { - "address": "0xB4e16d0168e52d35CaCD2c6185b44281Ec28C9Dc", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 USDC-ETH", - "network": "eth", - "shortcut": "univ2USDCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2USDCUSDT": { - "address": "0x3041CbD36888bECc7bbCBc0045E3B1f144466f5f", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 USDC-USDT", - "network": "eth", - "shortcut": "univ2USDCUSDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2VLINKETH": { - "address": "0xb06d43B9f8eb4e64e8C40f81e5574b8AEa6E1cb7", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 VLINK-ETH", - "network": "eth", - "shortcut": "univ2VLINKETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2VLTETH": { - "address": "0x966053Ca4fca049173eb1F27E4cb168CCb794534", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 VLT-ETH", - "network": "eth", - "shortcut": "univ2VLTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2VXVETH": { - "address": "0x0c9C5DAF1D7CD8B10e9fC5e7a10762f0a8d1C335", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 VXV-ETH", - "network": "eth", - "shortcut": "univ2VXVETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2WBOMBETH": { - "address": "0xEE89ea23c18410F2b57e7abc6eb24cfcdE4f49B0", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 WBOMB-ETH", - "network": "eth", - "shortcut": "univ2WBOMBETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2WBTCETH": { - "address": "0xBb2b8038a1640196FbE3e38816F3e67Cba72D940", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 WBTC-ETH", - "network": "eth", - "shortcut": "univ2WBTCETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2WINGSETH": { - "address": "0x06d5b7380C65c889abd82D3Df8aC118AF31156a1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 WINGS-ETH", - "network": "eth", - "shortcut": "univ2WINGSETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2XBASEETH": { - "address": "0x231F3381D10478BfC2cA552195b9d8B15968B60c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 XBASE-ETH", - "network": "eth", - "shortcut": "univ2XBASEETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2XIOETH": { - "address": "0xE0cc5aFc0FF2c76183416Fb8d1a29f6799FB2cdF", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 XIO-ETH", - "network": "eth", - "shortcut": "univ2XIOETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2XNSETH": { - "address": "0xB5bdb51fDC635359181111439Efe2799Bc2336c6", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 XNS-ETH", - "network": "eth", - "shortcut": "univ2XNSETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2XORETH": { - "address": "0x01962144D41415cCA072900Fe87Bbe2992A99F10", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 XOR-ETH", - "network": "eth", - "shortcut": "univ2XORETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2XRTETH": { - "address": "0x3185626c14aCB9531d19560dECb9d3E5E80681b1", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 XRT-ETH", - "network": "eth", - "shortcut": "univ2XRTETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2YFIETH": { - "address": "0x2fDbAdf3C4D5A8666Bc06645B8358ab803996E28", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 YFI-ETH", - "network": "eth", - "shortcut": "univ2YFIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2YFIIETH": { - "address": "0x8973Be4402bf0a39448f419c2D64bD3591Dd2299", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 YFII-ETH", - "network": "eth", - "shortcut": "univ2YFIIETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2sETHETH": { - "address": "0x598E740cda7C525080d3FCb9Fa7C4E1bd0044B34", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 sETH-ETH", - "network": "eth", - "shortcut": "univ2sETHETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2sUSDETH": { - "address": "0xf80758aB42C3B07dA84053Fd88804bCB6BAA4b5c", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 sUSD-ETH", - "network": "eth", - "shortcut": "univ2sUSDETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2sXAUUSDC": { - "address": "0x34a0216C5057bC18e5d34D4405284564eFd759b2", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 sXAU-USDC", - "network": "eth", - "shortcut": "univ2sXAUUSDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2uTOPIAETH": { - "address": "0x1a5314C1b3E17a781AaEF180BBa446d10E506E6B", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 uTOPIA-ETH", - "network": "eth", - "shortcut": "univ2uTOPIAETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:univ2wNXMETH": { - "address": "0x23bFf8ca20AAc06EFDf23cEe3B8ae296A30Dfd27", - "links": { - "Github": "https://github.com/Uniswap", - "Homepage": "https://www.uniswap.org" - }, - "marketcap_usd": 0, - "name": "Uniswap V2 wNXM-ETH", - "network": "eth", - "shortcut": "univ2wNXMETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usBAT": { - "address": "0x285f585106d15a313e7E6155Be4C5557d2deAAB1", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT", - "network": "eth", - "shortcut": "usBAT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usBAT2x": { - "address": "0x077539371bFa52a4194De833174D85ce218DBe3e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 2x", - "network": "eth", - "shortcut": "usBAT2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usBAT3x": { - "address": "0x071Bad913FC41eD10f617C8bbB4D12a4b4E544C5", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 3x", - "network": "eth", - "shortcut": "usBAT3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usBAT4x": { - "address": "0x20222979117A9B39030048423557A61eB5aBD681", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short BAT 4x", - "network": "eth", - "shortcut": "usBAT4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usETH": { - "address": "0x29B9723A3D88fe4a0B78134FD209433443A36b23", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ETH", - "network": "eth", - "shortcut": "usETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usETH2x": { - "address": "0x3263B85A9E52CDae86E9B1560e2e04fB357c42AC", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ETH 2x", - "network": "eth", - "shortcut": "usETH2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usETH3x": { - "address": "0x18Fab5aFF3B3bb8AfB0840861d831C228C1cb68f", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ETH 3x", - "network": "eth", - "shortcut": "usETH3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usETH4x": { - "address": "0x0eBf28c5252124B898EcaA41A15Ca40db9Bf2bFc", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ETH 4x", - "network": "eth", - "shortcut": "usETH4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usKNC": { - "address": "0xa148AC0aF78B83b7c2CbD0caE93fBfb5DDE3EA1a", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC", - "network": "eth", - "shortcut": "usKNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usKNC2x": { - "address": "0x41750Acb926BDE7bc1DF6d21690d64EDFF9f20E7", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 2x", - "network": "eth", - "shortcut": "usKNC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usKNC3x": { - "address": "0x4052Ea0a92Be6a3fBEC83DCb0c96264377127805", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 3x", - "network": "eth", - "shortcut": "usKNC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usKNC4x": { - "address": "0xc8CC7e53e35cDa71af098360E800e9bB2Ee88F9e", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short KNC 4x", - "network": "eth", - "shortcut": "usKNC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usREP": { - "address": "0xdBb0965046e142b4306ac453c7700BF768D6aC33", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP", - "network": "eth", - "shortcut": "usREP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usREP2x": { - "address": "0x9d94CAFb3cc67C5EfE660Fc988c51ABB711Cb7cA", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 2x", - "network": "eth", - "shortcut": "usREP2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usREP3x": { - "address": "0x5AD7BBb48b852c1C798BDB99911CBd59a5bFacfE", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 3x", - "network": "eth", - "shortcut": "usREP3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usREP4x": { - "address": "0x7eE12ffF0A8f975fCA5193825c215612A0eb07b7", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short REP 4x", - "network": "eth", - "shortcut": "usREP4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usWBTC": { - "address": "0x9DFC724c04f3ef1B9D539DCD0f8e4391A8b86FA1", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC", - "network": "eth", - "shortcut": "usWBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usWBTC2x": { - "address": "0x734317817bCf7254E6728B5A448A981D57d0a4fa", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 2x", - "network": "eth", - "shortcut": "usWBTC2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usWBTC3x": { - "address": "0xf7F59e42eea2F2F4DB6d54Ca87d5a17111ae1a7f", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 3x", - "network": "eth", - "shortcut": "usWBTC3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usWBTC4x": { - "address": "0x319ACBdB595867C1DC6aB9C5278Ea937aCDBeC58", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short WBTC 4x", - "network": "eth", - "shortcut": "usWBTC4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usZRX": { - "address": "0x43baf2ec0C4236B661a84FD40EC076546E3Bb9Fd", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX", - "network": "eth", - "shortcut": "usZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usZRX2x": { - "address": "0xcedf540D158eB62dfdcde8398c3037b54705BcEB", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 2x", - "network": "eth", - "shortcut": "usZRX2x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usZRX3x": { - "address": "0x903214d3d3616d8Dc5cCB3d40A435DcA08F08010", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 3x", - "network": "eth", - "shortcut": "usZRX3x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:usZRX4x": { - "address": "0xde37db4269C6dfD4c81B9A11400d1BcBEeC06515", - "links": { - "Github": "https://github.com/bZxNetwork", - "Homepage": "https://bzx.network/" - }, - "marketcap_usd": 0, - "name": "bZx Perpetual Short ZRX 4x", - "network": "eth", - "shortcut": "usZRX4x", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:eth:veOGV": { - "address": "0x0C4576Ca1c365868E162554AF8e385dc3e7C66D9", - "links": { - "Github": "https://github.com/OriginProtocol/ousd-governance", - "Homepage": "https://governance.ousd.com" - }, - "marketcap_usd": 0, - "name": "Vote Escrowed Origin Dollar Governance", - "network": "eth", - "shortcut": "veOGV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "erc20:kov:DAI": { - "address": "0xC4375B7De8af5a38a93548eb8453a498222C4fF2", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test Dai Stablecoin v1.0", - "network": "kov", - "shortcut": "DAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:DGD": { - "address": "0xeeE3870657E4716670f185dF08652dd848fe8f7e", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test Digix DAO Token", - "network": "kov", - "shortcut": "DGD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:GNT": { - "address": "0xeF7FfF64389B814A946f3E92105513705CA6B990", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test Golem Network Token", - "network": "kov", - "shortcut": "GNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:MKR:1dad": { - "address": "0x1Dad4783cf3fe3085C1426157aB175A6119A04bA", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test MakerDAO", - "network": "kov", - "shortcut": "MKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:MKR:aaf6": { - "address": "0xAaF64BFCC32d0F15873a02163e7E500671a4ffcD", - "links": { - "Github": "https://github.com/makerdao", - "Homepage": "https://makerdao.com" - }, - "marketcap_usd": 0, - "name": "MakerDAO", - "network": "kov", - "shortcut": "MKR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:MLN": { - "address": "0x323B5d4C32345ced77393B3530b1EeD0f346429D", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test Melon Tokens", - "network": "kov", - "shortcut": "MLN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:REP": { - "address": "0xB18845c260F680d5B9D84649638813E342E4F8C9", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test Augur Reputation Token", - "network": "kov", - "shortcut": "REP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:RLC": { - "address": "0xc57538846Ec405Ea25Deb00e0f9B29a432D53507", - "links": { - "Github": "https://github.com/iExecBlockchainComputing/", - "Homepage": "https://iex.ec" - }, - "marketcap_usd": 0, - "name": "iExec RLC", - "network": "kov", - "shortcut": "RLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:kov:ZRX": { - "address": "0x6Ff6C0Ff1d68b964901F986d4C9FA3ac68346570", - "links": { - "Homepage": "https://faucet.kovan.radarrelay.com" - }, - "marketcap_usd": 0, - "name": "RadarRelay test 0x Protocol Token", - "network": "kov", - "shortcut": "ZRX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:AETH": { - "address": "0x398A7A69f3c59181A1ffe34bed11DCb5DF863A8a", - "links": { - "Github": "https://github.com/akashaProject", - "Homepage": "http://akasha.world" - }, - "marketcap_usd": 0, - "name": "AKASHA Tokens", - "network": "rin", - "shortcut": "AETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:BHNT": { - "address": "0xe27826eE778B6F78a49a686dA7D64f6E7b084a4f", - "links": { - "Github": "https://github.com/berlin-hack-and-tell", - "Homepage": "http://berlin.hackandtell.org" - }, - "marketcap_usd": 0, - "name": "Berlin Hack&Tell winner token", - "network": "rin", - "shortcut": "BHNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:CTGA": { - "address": "0x8B65d4B7ee3FFFA986C577F0F4b70a21BaE3dD54", - "links": { - "Homepage": "https://www.ctgcoin.org" - }, - "marketcap_usd": 0, - "name": "Convenient To Go", - "network": "rin", - "shortcut": "CTGA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:KC": { - "address": "0x275A5B346599b56917e7B1C9de019DCf9EaD861a", - "links": { - "Homepage": "https://baseblock.io/" - }, - "marketcap_usd": 0, - "name": "Karma Token", - "network": "rin", - "shortcut": "KC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:RDN": { - "address": "0x3615757011112560521536258c1E7325Ae3b48AE", - "links": { - "Homepage": "https://github.com/gnosis/dx-examples-liquidity-bots" - }, - "marketcap_usd": 0, - "name": "Raiden", - "network": "rin", - "shortcut": "RDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:RLC": { - "address": "0xf1e6Ad3a7eF0c86c915F0feDF80eD851809bEA90", - "links": { - "Github": "https://github.com/iExecBlockchainComputing/", - "Homepage": "https://iex.ec" - }, - "marketcap_usd": 0, - "name": "iExec RLC", - "network": "rin", - "shortcut": "RLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rin:WALL": { - "address": "0x0A057a87CE9C56D7e336B417c79cf30E8d27860B", - "links": { - "Github": "https://github.com/walleth", - "Homepage": "https://walleth.org" - }, - "marketcap_usd": 0, - "name": "WALLETH Community-Token", - "network": "rin", - "shortcut": "WALL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rop:RLC": { - "address": "0x7314Dc4d7794b5E7894212CA1556ae8e3De58621", - "links": { - "Github": "https://github.com/iExecBlockchainComputing/", - "Homepage": "https://iex.ec" - }, - "marketcap_usd": 0, - "name": "iExec RLC", - "network": "rop", - "shortcut": "RLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rop:dqr30": { - "address": "0xa1bAccA0e12D4091Ec1f92e7CaE3394CC9854D3D", - "links": { - "Homepage": "https://dqr-group.com/" - }, - "marketcap_usd": 0, - "name": "DQR", - "network": "rop", - "shortcut": "dqr30", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:BITP": { - "address": "0x440CD83C160De5C96Ddb20246815eA44C7aBBCa8", - "links": { - "Github": "https://github.com/money-on-chain/", - "Homepage": "https://moneyonchain.com/bpro-hodl-earn-token" - }, - "marketcap_usd": 0, - "name": "BitPro", - "network": "rsk", - "shortcut": "BITP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:BRZ": { - "address": "0xE355c280131dFaF18Bf1c3648aEe3C396dB6b5Fd", - "links": { - "Homepage": "https://www.brztoken.io" - }, - "marketcap_usd": 0, - "name": "Brezilian Digital Coin", - "network": "rsk", - "shortcut": "BRZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:DOC": { - "address": "0xe700691dA7b9851F2F35f8b8182c69c53CcaD9Db", - "links": { - "Github": "https://github.com/money-on-chain/", - "Homepage": "https://moneyonchain.com/doc-bitcoin-backed-stablecoin" - }, - "marketcap_usd": 0, - "name": "Dollar on Chain", - "network": "rsk", - "shortcut": "DOC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:FISH": { - "address": "0x055A902303746382FBB7D18f6aE0df56eFDc5213", - "links": { - "Github": "https://github.com/BabelFishProtocol/babelfish-phase-1", - "Homepage": "https://babelfish.money" - }, - "marketcap_usd": 0, - "name": "Babelfish", - "network": "rsk", - "shortcut": "FISH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:RIF": { - "address": "0x2AcC95758f8b5F583470ba265EB685a8F45fC9D5", - "links": { - "Github": "https://github.com/riflabs", - "Homepage": "https://rifos.org" - }, - "marketcap_usd": 0, - "name": "RIF Token", - "network": "rsk", - "shortcut": "RIF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:SOV": { - "address": "0xEFc78fc7d48b64958315949279Ba181c2114ABBd", - "links": { - "Github": "https://github.com/DistributedCollective", - "Homepage": "https://www.sovryn.app" - }, - "marketcap_usd": 0, - "name": "Sovryn Token", - "network": "rsk", - "shortcut": "SOV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:rsk:XUSD": { - "address": "0xb5999795BE0EbB5bAb23144AA5FD6A02D080299F", - "links": { - "Github": "https://github.com/BabelFishProtocol/babelfish-phase-1", - "Homepage": "https://babelfish.money" - }, - "marketcap_usd": 0, - "name": "XUSD Babelfish Stablecoin", - "network": "rsk", - "shortcut": "XUSD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:CEFS": { - "address": "0x08533D6A06CE365298b12Ef92eb407cBA8Aa8273", - "links": { - "Homepage": "https://www.cryptopiashares.com" - }, - "marketcap_usd": 0, - "name": "CEFS", - "network": "ubq", - "shortcut": "CEFS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:GEO": { - "address": "0x500684CE0D4f04aBeDff3e54fCF8acC5E6CFc4bD", - "links": { - "Homepage": "https://geo.money" - }, - "marketcap_usd": 0, - "name": "GeoCoin", - "network": "ubq", - "shortcut": "GEO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:GRANS": { - "address": "0x0826180A4c981d5095Cb5c48BB2A098A44cf6f73", - "links": { - "Homepage": "https://https://10grans.cash" - }, - "marketcap_usd": 0, - "name": "10grans", - "network": "ubq", - "shortcut": "GRANS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:INK": { - "address": "0x7845fCbE28ac19ab7ec1C1D9674E34fdCB4917Db", - "links": { - "Homepage": "https://tentacle.finance" - }, - "marketcap_usd": 0, - "name": "INK", - "network": "ubq", - "shortcut": "INK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:QWARK": { - "address": "0x4b4899a10F3E507DB207b0ee2426029eFa168a67", - "links": { - "Homepage": "https://www.qwark.io" - }, - "marketcap_usd": 0, - "name": "QWARK", - "network": "ubq", - "shortcut": "QWARK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:RICKS": { - "address": "0x5e1715bB79805Bd672729760B3f7F34D6f485098", - "links": { - "Homepage": "https://picklericks.wixsite.com/picklewix" - }, - "marketcap_usd": 0, - "name": "RICKS", - "network": "ubq", - "shortcut": "RICKS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "erc20:ubq:SNARG": { - "address": "0x497E20586F86c35592FF8F65CdE94F296514C387", - "links": { - "Homepage": "https://snarg01.horse" - }, - "marketcap_usd": 0, - "name": "Snarg01", - "network": "ubq", - "shortcut": "SNARG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "erc20", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:$BNI": { - "links": { - "Homepage": "https://bitindi.org" - }, - "marketcap_usd": 0, - "name": "Bitindi", - "shortcut": "$BNI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:$OC": { - "links": { - "Homepage": "https://digitalnext.business/SocialSmartChain" - }, - "marketcap_usd": 0, - "name": "Social Smart Chain", - "shortcut": "$OC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:0XT": { - "links": { - "Homepage": "https://www.0xtrade.finance/" - }, - "marketcap_usd": 0, - "name": "0XTade", - "shortcut": "0XT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:0xF": { - "links": { - "Homepage": "https://freighttrust.com" - }, - "marketcap_usd": 0, - "name": "Freight Trust Network", - "shortcut": "0xF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AAC": { - "links": { - "Homepage": "https://www.acuteangle.com/" - }, - "marketcap_usd": 0, - "name": "Double-A Chain", - "shortcut": "AAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ACA": { - "links": { - "Homepage": "https://acala.network" - }, - "marketcap_usd": 0, - "name": "Acala Network", - "shortcut": "ACA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ACE": { - "links": { - "Homepage": "https://ace.fusionist.io/" - }, - "marketcap_usd": 0, - "name": "Endurance Smart Chain", - "shortcut": "ACE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AIOZ": { - "links": { - "Homepage": "https://aioz.network" - }, - "marketcap_usd": 33770520, - "name": "AIOZ Network", - "shortcut": "AIOZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AITD": { - "links": { - "Homepage": "https://www.aitd.io/" - }, - "marketcap_usd": 0, - "name": "Aitd", - "shortcut": "AITD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AKA": { - "links": { - "Homepage": "https://akroma.io" - }, - "marketcap_usd": 22416, - "name": "Akroma", - "shortcut": "AKA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ALOT": { - "links": { - "Homepage": "https://dexalot.com" - }, - "marketcap_usd": 0, - "name": "Dexalot Subnet", - "shortcut": "ALOT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ALPH": { - "links": { - "Homepage": "https://alph.network" - }, - "marketcap_usd": 0, - "name": "Alph Network", - "shortcut": "ALPH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ALT": { - "links": { - "Homepage": "https://altcoinchain.org" - }, - "marketcap_usd": 0, - "name": "Altcoinchain", - "shortcut": "ALT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ALYX": { - "links": { - "Homepage": "https://www.alyxchain.com" - }, - "marketcap_usd": 0, - "name": "Alyx", - "shortcut": "ALYX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AMAX": { - "links": { - "Homepage": "https://amax.network" - }, - "marketcap_usd": 0, - "name": "Armonia Eva Chain", - "shortcut": "AMAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AMB": { - "links": { - "Homepage": "https://airdao.io" - }, - "marketcap_usd": 27921475, - "name": "AirDAO", - "shortcut": "AMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AMBROS": { - "links": { - "Homepage": "https://ambros.network" - }, - "marketcap_usd": 0, - "name": "Ambros Chain", - "shortcut": "AMBROS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AME": { - "links": { - "Homepage": "https://amechain.io/" - }, - "marketcap_usd": 0, - "name": "AME Chain", - "shortcut": "AME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ANY": { - "links": { - "Homepage": "https://evm.anytype.io" - }, - "marketcap_usd": 0, - "name": "Anytype EVM Chain", - "shortcut": "ANY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:APTA": { - "links": { - "Homepage": "https://bloqs4good.com" - }, - "marketcap_usd": 0, - "name": "4GoodNetwork", - "shortcut": "APTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AQUA": { - "links": { - "Homepage": "https://aquachain.github.io" - }, - "marketcap_usd": 0, - "name": "Aquachain", - "shortcut": "AQUA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AR\u00c9V": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "Arevia", - "shortcut": "AR\u00c9V", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ASA": { - "links": { - "Homepage": "https://astranaut.io" - }, - "marketcap_usd": 0, - "name": "Astra", - "shortcut": "ASA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ASK": { - "links": { - "Homepage": "https://permission.io/" - }, - "marketcap_usd": 0, - "name": "Permission", - "shortcut": "ASK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ASTR": { - "links": { - "Homepage": "https://astar.network/" - }, - "marketcap_usd": 328182166, - "name": "Astar", - "shortcut": "ASTR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ATLR": { - "links": { - "Homepage": "https://1971.network/" - }, - "marketcap_usd": 0, - "name": "Atelier", - "shortcut": "ATLR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ATS": { - "links": { - "Homepage": "https://artis.eco" - }, - "marketcap_usd": 0, - "name": "ARTIS sigma1", - "shortcut": "ATS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AUX": { - "links": { - "Github": "https://github.com/auxiliumglobal", - "Homepage": "https://auxilium.global" - }, - "marketcap_usd": 0, - "name": "Auxilium Network", - "shortcut": "AUX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - } - ] - }, - "eth:AVAX": { - "links": { - "Homepage": "https://www.avax.network/" - }, - "marketcap_usd": 0, - "name": "Avalanche C-Chain", - "shortcut": "AVAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:AVS": { - "links": { - "Homepage": "https://avescoin.io" - }, - "marketcap_usd": 0, - "name": "Aves", - "shortcut": "AVS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BCS": { - "links": { - "Homepage": "https://blockchainstation.io" - }, - "marketcap_usd": 0, - "name": "BlockChain Station", - "shortcut": "BCS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BELLY": { - "links": { - "Homepage": "https://cryptopiece.online" - }, - "marketcap_usd": 0, - "name": "Openpiece", - "shortcut": "BELLY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BFC": { - "links": { - "Homepage": "https://thebifrost.io" - }, - "marketcap_usd": 94426967, - "name": "Bifrost", - "shortcut": "BFC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BG": { - "links": { - "Homepage": "https://beagle.chat/" - }, - "marketcap_usd": 0, - "name": "Beagle Messaging Chain", - "shortcut": "BG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BIT": { - "links": { - "Homepage": "https://mantle.xyz" - }, - "marketcap_usd": 0, - "name": "Mantle", - "shortcut": "BIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BITCI": { - "links": { - "Homepage": "https://www.bitcichain.com" - }, - "marketcap_usd": 0, - "name": "Bitcichain", - "shortcut": "BITCI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BNB": { - "links": { - "Homepage": "https://www.binance.org" - }, - "marketcap_usd": 47729156144, - "name": "Binance Smart Chain", - "shortcut": "BNB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BOA": { - "links": { - "Homepage": "https://docs.bosagora.org" - }, - "marketcap_usd": 10622097, - "name": "BOSagora", - "shortcut": "BOA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BOMB": { - "links": { - "Homepage": "https://www.bombchain.com" - }, - "marketcap_usd": 108635, - "name": "BOMB Chain", - "shortcut": "BOMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BOY": { - "links": { - "Homepage": "https://boyanet.org" - }, - "marketcap_usd": 0, - "name": "BON Network", - "shortcut": "BOY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BRB": { - "links": { - "Homepage": "https://www.beryl-bit.com" - }, - "marketcap_usd": 0, - "name": "BerylBit", - "shortcut": "BRB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BRNKC": { - "links": { - "Homepage": "https://bearnetwork.net" - }, - "marketcap_usd": 0, - "name": "Bear Network Chain", - "shortcut": "BRNKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTA": { - "links": { - "Homepage": "https://bitcoinasset.io/" - }, - "marketcap_usd": 0, - "name": "Btachain", - "shortcut": "BTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTCIX": { - "links": { - "Homepage": "https://bitcolojix.org" - }, - "marketcap_usd": 0, - "name": "BTCIX Network", - "shortcut": "BTCIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTM": { - "links": { - "Homepage": "https://bmc.bytom.io/" - }, - "marketcap_usd": 0, - "name": "BMC", - "shortcut": "BTM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTON": { - "links": { - "Homepage": "https://blocktoncoin.com" - }, - "marketcap_usd": 0, - "name": "Blockton Blockchain", - "shortcut": "BTON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTT": { - "links": { - "Homepage": "https://bittorrentchain.io/" - }, - "marketcap_usd": 0, - "name": "BitTorrent Chain", - "shortcut": "BTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BTY": { - "links": { - "Homepage": "https://www.bityuan.com" - }, - "marketcap_usd": 0, - "name": "BitYuan", - "shortcut": "BTY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:BXN": { - "links": { - "Homepage": "https://blackfort.exchange" - }, - "marketcap_usd": 0, - "name": "BlackFort Exchange Network", - "shortcut": "BXN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:Brise": { - "links": { - "Homepage": "https://bitgert.com/" - }, - "marketcap_usd": 0, - "name": "Bitgert", - "shortcut": "Brise", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CAM:500": { - "links": { - "Homepage": "https://camino.foundation/" - }, - "marketcap_usd": 0, - "name": "Camino C-Chain", - "shortcut": "CAM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CANTO": { - "links": { - "Homepage": "https://canto.io" - }, - "marketcap_usd": 0, - "name": "Canto", - "shortcut": "CANTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CATE": { - "links": { - "Homepage": "https://catechain.com" - }, - "marketcap_usd": 0, - "name": "Catecoin Chain", - "shortcut": "CATE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CCNA": { - "links": { - "Homepage": "https://oortech.com" - }, - "marketcap_usd": 0, - "name": "Oort Ascraeus", - "shortcut": "CCNA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CCP": { - "links": { - "Homepage": "https://www.cryptocoinpay.co" - }, - "marketcap_usd": 0, - "name": "CryptoCoinPay", - "shortcut": "CCP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CELO": { - "links": { - "Homepage": "https://docs.celo.org/" - }, - "marketcap_usd": 370021788, - "name": "Celo", - "shortcut": "CELO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CEM": { - "links": { - "Homepage": "https://cemblockchain.com/" - }, - "marketcap_usd": 0, - "name": "Crypto Emergency", - "shortcut": "CEM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CFX": { - "links": { - "Homepage": "https://confluxnetwork.org" - }, - "marketcap_usd": 0, - "name": "Conflux eSpace", - "shortcut": "CFX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CIC": { - "links": { - "Homepage": "https://www.cicchain.net" - }, - "marketcap_usd": 0, - "name": "CIC Chain", - "shortcut": "CIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CLASS": { - "links": { - "Homepage": "https://velaverse.io" - }, - "marketcap_usd": 0, - "name": "Vela1 Chain", - "shortcut": "CLASS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CLD": { - "links": { - "Homepage": "https://cloudtx.finance" - }, - "marketcap_usd": 0, - "name": "CloudTx", - "shortcut": "CLD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CLO": { - "coinmarketcap_alias": "callisto-network", - "links": { - "Homepage": "https://callisto.network" - }, - "marketcap_usd": 9476443, - "name": "Callisto", - "shortcut": "CLO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CLV": { - "links": { - "Homepage": "https://clv.org" - }, - "marketcap_usd": 0, - "name": "CLV Parachain", - "shortcut": "CLV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CMEMO": { - "links": { - "Homepage": "www.memolabs.org" - }, - "marketcap_usd": 0, - "name": "Memo Smart Chain", - "shortcut": "CMEMO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CMP": { - "links": { - "Homepage": "https://caduceus.foundation/" - }, - "marketcap_usd": 0, - "name": "CMP-Mainnet", - "shortcut": "CMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CNDL": { - "links": { - "Homepage": "https://candlelabs.org/" - }, - "marketcap_usd": 0, - "name": "Candle", - "shortcut": "CNDL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CONDOR": { - "links": { - "Homepage": "https://condor.systems" - }, - "marketcap_usd": 0, - "name": "Condor Test Network", - "shortcut": "CONDOR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CORE": { - "links": { - "Homepage": "https://www.coredao.org" - }, - "marketcap_usd": 0, - "name": "Core Blockchain", - "shortcut": "CORE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CPAY:21337": { - "links": { - "Homepage": "https://cennz.net" - }, - "marketcap_usd": 0, - "name": "CENNZnet Azalea", - "shortcut": "CPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CPAY:3000": { - "links": { - "Homepage": "https://cennz.net" - }, - "marketcap_usd": 0, - "name": "CENNZnet Rata", - "shortcut": "CPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CPAY:3001": { - "links": { - "Homepage": "https://cennz.net" - }, - "marketcap_usd": 0, - "name": "CENNZnet Nikau", - "shortcut": "CPAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CRAB": { - "links": { - "Homepage": "https://crab.network/" - }, - "marketcap_usd": 0, - "name": "Darwinia Crab Network", - "shortcut": "CRAB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CRC": { - "links": { - "Homepage": "https://github.com/ethereum-pocr/pocrnet" - }, - "marketcap_usd": 0, - "name": "PoCRNet", - "shortcut": "CRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CREDIT": { - "links": { - "Homepage": "https://creditsmartchain.com" - }, - "marketcap_usd": 238095, - "name": "Credit Smartchain", - "shortcut": "CREDIT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CRO": { - "links": { - "Homepage": "https://cronos.org/" - }, - "marketcap_usd": 2011736262, - "name": "Cronos", - "shortcut": "CRO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CSB": { - "links": { - "Homepage": "https://crossbell.io" - }, - "marketcap_usd": 0, - "name": "Crossbell", - "shortcut": "CSB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CTEX": { - "links": { - "Homepage": "https://ctextoken.io" - }, - "marketcap_usd": 0, - "name": "Ctex Scan Blockchain", - "shortcut": "CTEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CUBE": { - "links": { - "Homepage": "https://www.cube.network" - }, - "marketcap_usd": 0, - "name": "Cube Chain", - "shortcut": "CUBE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:CWN": { - "links": { - "Homepage": "https://cloudwalk.io" - }, - "marketcap_usd": 0, - "name": "CloudWalk", - "shortcut": "CWN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DAX": { - "links": { - "Homepage": "https://prodax.io/" - }, - "marketcap_usd": 0, - "name": "DAX CHAIN", - "shortcut": "DAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DEB": { - "links": { - "Homepage": "https://anduschain.io/" - }, - "marketcap_usd": 0, - "name": "Anduschain", - "shortcut": "DEB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DEL": { - "links": { - "Homepage": "https://decimalchain.com" - }, - "marketcap_usd": 0, - "name": "Decimal Smart Chain", - "shortcut": "DEL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DEV": { - "links": { - "Homepage": "https://docs.moonbeam.network/networks/testnet/" - }, - "marketcap_usd": 0, - "name": "Moonbase Alpha", - "shortcut": "DEV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DFI": { - "links": { - "Homepage": "https://meta.defichain.com/" - }, - "marketcap_usd": 0, - "name": "DeFiChain EVM Network", - "shortcut": "DFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DIODE": { - "links": { - "Homepage": "https://diode.io/prenet" - }, - "marketcap_usd": 0, - "name": "Diode Prenet", - "shortcut": "DIODE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DKN": { - "links": { - "Homepage": "https://doken.dev/" - }, - "marketcap_usd": 0, - "name": "DoKEN Super Chain", - "shortcut": "DKN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DOGS": { - "links": { - "Homepage": "https://dogcoin.network" - }, - "marketcap_usd": 0, - "name": "Dogcoin", - "shortcut": "DOGS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DOINX": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "D-Chain", - "shortcut": "DOINX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DOS": { - "links": { - "Homepage": "http://doschain.io/" - }, - "marketcap_usd": 0, - "name": "Dos Fuji Subnet", - "shortcut": "DOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DRAC": { - "links": { - "Homepage": "https://drac.io/" - }, - "marketcap_usd": 0, - "name": "DRAC Network", - "shortcut": "DRAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DWU": { - "links": { - "Homepage": "https://decentralized-web.tech/dw_chain.php" - }, - "marketcap_usd": 0, - "name": "Decentralized Web", - "shortcut": "DWU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DX": { - "links": { - "Homepage": "https://www.dxchain.com/" - }, - "marketcap_usd": 0, - "name": "Dxchain", - "shortcut": "DX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DXT": { - "links": { - "Homepage": "https://dexit.network" - }, - "marketcap_usd": 0, - "name": "Dexit Network", - "shortcut": "DXT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:DYNO": { - "links": { - "Homepage": "https://dynoprotocol.com" - }, - "marketcap_usd": 0, - "name": "DYNO", - "shortcut": "DYNO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:Deh": { - "links": { - "Homepage": "https://dehvo.com" - }, - "marketcap_usd": 0, - "name": "Dehvo", - "shortcut": "Deh", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ECG": { - "links": { - "Homepage": "https://ssquad.games/" - }, - "marketcap_usd": 0, - "name": "SPS", - "shortcut": "ECG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ECO": { - "links": { - "Homepage": "https://ecoball.org" - }, - "marketcap_usd": 0, - "name": "Ecoball", - "shortcut": "ECO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ECS": { - "links": { - "Homepage": "https://ecredits.com" - }, - "marketcap_usd": 0, - "name": "eCredits", - "shortcut": "ECS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EDG": { - "links": { - "Homepage": "http://edgewa.re" - }, - "marketcap_usd": 4689635, - "name": "Edgeware", - "shortcut": "EDG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EGAZ": { - "links": { - "Homepage": "https://eticaprotocol.org" - }, - "marketcap_usd": 0, - "name": "Etica", - "shortcut": "EGAZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EGEM": { - "links": { - "Homepage": "https://egem.io" - }, - "marketcap_usd": 36379, - "name": "EtherGem", - "shortcut": "EGEM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EIDI": { - "links": { - "Homepage": "https://idchain.one/begin/" - }, - "marketcap_usd": 0, - "name": "IDChain", - "shortcut": "EIDI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EKTA": { - "links": { - "Homepage": "https://www.ekta.io" - }, - "marketcap_usd": 239141, - "name": "Ekta", - "shortcut": "EKTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ELA:20": { - "links": { - "Homepage": "https://www.elastos.org/" - }, - "marketcap_usd": 0, - "name": "Elastos Smart Chain", - "shortcut": "ELA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ELV": { - "links": { - "Homepage": "https://eluv.io" - }, - "marketcap_usd": 0, - "name": "Eluvio Content Fabric", - "shortcut": "ELV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EMPIRE": { - "links": { - "Homepage": "https://www.empirenetwork.io/" - }, - "marketcap_usd": 0, - "name": "Empire Network", - "shortcut": "EMPIRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ENTER": { - "links": { - "Homepage": "https://entercoin.net" - }, - "marketcap_usd": 0, - "name": "EnterChain", - "shortcut": "ENTER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ES": { - "links": { - "Homepage": "https://eraswap.info/" - }, - "marketcap_usd": 0, - "name": "EraSwap", - "shortcut": "ES", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ESN": { - "coinmarketcap_alias": "ethersocial", - "links": { - "Homepage": "https://ethersocial.org" - }, - "marketcap_usd": 0, - "name": "Ethersocial Network", - "shortcut": "ESN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETC": { - "links": { - "Homepage": "https://ethereumclassic.org" - }, - "marketcap_usd": 2950948570, - "name": "Ethereum Classic", - "shortcut": "ETC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "eth:ETH:1": { - "links": { - "Homepage": "https://ethereum.org" - }, - "marketcap_usd": 199115648941, - "name": "Ethereum", - "shortcut": "ETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "eth:ETHF": { - "links": { - "Homepage": "https://etherfair.org" - }, - "marketcap_usd": 0, - "name": "ethereum Fair", - "shortcut": "ETHF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETHO": { - "links": { - "Homepage": "https://ethoprotocol.com" - }, - "marketcap_usd": 910129, - "name": "Etho Protocol", - "shortcut": "ETHO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETI": { - "links": { - "Homepage": "https://einc.io" - }, - "marketcap_usd": 0, - "name": "EtherInc", - "shortcut": "ETI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETL": { - "links": { - "Homepage": "https://etherlite.org" - }, - "marketcap_usd": 0, - "name": "EtherLite Chain", - "shortcut": "ETL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETMP": { - "links": { - "Homepage": "https://etm.network" - }, - "marketcap_usd": 0, - "name": "Ennothem", - "shortcut": "ETMP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ETND": { - "links": { - "Homepage": "https://www.etnd.pro" - }, - "marketcap_usd": 0, - "name": "ETND Chain", - "shortcut": "ETND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EUN": { - "links": { - "Homepage": "https://eurus.network" - }, - "marketcap_usd": 0, - "name": "Eurus", - "shortcut": "EUN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EVA": { - "links": { - "Homepage": "https://evanesco.org/" - }, - "marketcap_usd": 0, - "name": "Evanesco", - "shortcut": "EVA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EVC": { - "links": { - "Homepage": "https://evrice.com" - }, - "marketcap_usd": 0, - "name": "Evrice Network", - "shortcut": "EVC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EVMOS": { - "links": { - "Homepage": "https://evmos.org" - }, - "marketcap_usd": 0, - "name": "Evmos", - "shortcut": "EVMOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EWT": { - "links": { - "Homepage": "https://energyweb.org" - }, - "marketcap_usd": 0, - "name": "Energy Web Chain", - "shortcut": "EWT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EXL": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "Excoincial Chain", - "shortcut": "EXL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EXP": { - "links": { - "Homepage": "https://expanse.tech" - }, - "marketcap_usd": 0, - "name": "Expanse Network", - "shortcut": "EXP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:EZC": { - "links": { - "Homepage": "https://ezchain.com" - }, - "marketcap_usd": 0, - "name": "EZChain C-Chain", - "shortcut": "EZC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FETH": { - "links": { - "Homepage": "https://www.factory127.com" - }, - "marketcap_usd": 0, - "name": "Factory 127", - "shortcut": "FETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FIL": { - "links": { - "Homepage": "https://filecoin.io" - }, - "marketcap_usd": 0, - "name": "Filecoin -", - "shortcut": "FIL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FIN": { - "links": { - "Homepage": "https://primusmoney.com" - }, - "marketcap_usd": 0, - "name": "Firenze test network", - "shortcut": "FIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FIRE:529": { - "links": { - "Homepage": "https://thefirechain.com" - }, - "marketcap_usd": 0, - "name": "Firechain", - "shortcut": "FIRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FITFI": { - "links": { - "Homepage": "https://step.network" - }, - "marketcap_usd": 0, - "name": "Step Network", - "shortcut": "FITFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FLA": { - "links": { - "Homepage": "https://www.flaexchange.top" - }, - "marketcap_usd": 0, - "name": "Flachain", - "shortcut": "FLA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FLR": { - "links": { - "Homepage": "https://flare.xyz" - }, - "marketcap_usd": 467857625, - "name": "Flare", - "shortcut": "FLR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FNCY": { - "links": { - "Homepage": "https://fncyscan.fncy.world" - }, - "marketcap_usd": 38806503, - "name": "FNCY", - "shortcut": "FNCY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FREN": { - "links": { - "Homepage": "https://frenchain.app" - }, - "marketcap_usd": 0, - "name": "Frenchain", - "shortcut": "FREN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FSN": { - "links": { - "Homepage": "https://fusion.org" - }, - "marketcap_usd": 26079174, - "name": "Fusion", - "shortcut": "FSN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FST": { - "links": { - "Homepage": "https://fantasia.technology/" - }, - "marketcap_usd": 0, - "name": "Fantasia Chain", - "shortcut": "FST", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FTM": { - "links": { - "Homepage": "https://fantom.foundation" - }, - "marketcap_usd": 0, - "name": "Fantom Opera", - "shortcut": "FTM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FUSE": { - "links": { - "Homepage": "https://fuse.io/" - }, - "marketcap_usd": 0, - "name": "Fuse", - "shortcut": "FUSE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:FX": { - "links": { - "Homepage": "https://functionx.io/" - }, - "marketcap_usd": 0, - "name": "F(x)Core", - "shortcut": "FX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GAR:90": { - "links": { - "Homepage": "https://garizon.com" - }, - "marketcap_usd": 0, - "name": "Garizon Stage0", - "shortcut": "GAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GCD": { - "links": { - "Homepage": "https://gton.capital" - }, - "marketcap_usd": 0, - "name": "GTON", - "shortcut": "GCD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GEN": { - "links": { - "Homepage": "https://www.xixoio.com/" - }, - "marketcap_usd": 0, - "name": "Blockchain Genesis", - "shortcut": "GEN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GLMR": { - "links": { - "Homepage": "https://moonbeam.network/networks/moonbeam/" - }, - "marketcap_usd": 255322438, - "name": "Moonbeam", - "shortcut": "GLMR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GLQ": { - "links": { - "Homepage": "https://graphlinq.io" - }, - "marketcap_usd": 0, - "name": "Graphlinq Blockchain", - "shortcut": "GLQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GMMT": { - "links": { - "Homepage": "https://gmmtchain.io/" - }, - "marketcap_usd": 0, - "name": "Giant Mammoth", - "shortcut": "GMMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GNC": { - "links": { - "Homepage": "https://genesis-gn.com" - }, - "marketcap_usd": 0, - "name": "Genesis Coin", - "shortcut": "GNC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GO": { - "links": { - "Homepage": "https://gochain.io" - }, - "marketcap_usd": 9893895, - "name": "GoChain", - "shortcut": "GO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GOLDT": { - "links": { - "Homepage": "https://www.hammerchain.io" - }, - "marketcap_usd": 0, - "name": "Hammer Chain", - "shortcut": "GOLDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GZN": { - "links": { - "Homepage": "https://token.gearzero.ca/mainnet" - }, - "marketcap_usd": 0, - "name": "Gear Zero Network", - "shortcut": "GZN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:GooD": { - "links": { - "Homepage": "https://www.goodata.org" - }, - "marketcap_usd": 0, - "name": "GoodData", - "shortcut": "GooD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HAIC": { - "links": { - "Homepage": "https://www.haichain.io/" - }, - "marketcap_usd": 0, - "name": "Haic", - "shortcut": "HAIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HBAR:295": { - "links": { - "Homepage": "https://hedera.com" - }, - "marketcap_usd": 1876574858, - "name": "Hedera", - "shortcut": "HBAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HMND": { - "links": { - "Homepage": "https://humanode.io" - }, - "marketcap_usd": 0, - "name": "Humanode", - "shortcut": "HMND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HO": { - "links": { - "Homepage": "https://halo.land/#/" - }, - "marketcap_usd": 0, - "name": "HALO", - "shortcut": "HO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HOO": { - "links": { - "Homepage": "https://www.hoosmartchain.com" - }, - "marketcap_usd": 0, - "name": "Hoo Smart Chain", - "shortcut": "HOO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HOP": { - "links": { - "Homepage": "https://www.DataHopper.com" - }, - "marketcap_usd": 0, - "name": "DataHopper", - "shortcut": "HOP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HPB": { - "links": { - "Homepage": "https://hpb.io" - }, - "marketcap_usd": 957132, - "name": "High Performance Blockchain", - "shortcut": "HPB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HT": { - "links": { - "Homepage": "https://www.hecochain.com" - }, - "marketcap_usd": 0, - "name": "Huobi ECO Chain", - "shortcut": "HT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HTML": { - "links": { - "Homepage": "https://htmlcoin.com" - }, - "marketcap_usd": 0, - "name": "Htmlcoin", - "shortcut": "HTML", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:HTZ": { - "links": { - "Homepage": "https://www.hertz-network.com" - }, - "marketcap_usd": 124618, - "name": "Hertz Network", - "shortcut": "HTZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ILT": { - "links": { - "Homepage": "https://iolite.io" - }, - "marketcap_usd": 0, - "name": "IOLite", - "shortcut": "ILT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:IMV": { - "links": { - "Homepage": "https://imversed.com" - }, - "marketcap_usd": 0, - "name": "Imversed", - "shortcut": "IMV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:IORA": { - "links": { - "Homepage": "https://iorachain.com" - }, - "marketcap_usd": 0, - "name": "Iora Chain", - "shortcut": "IORA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:IOTX": { - "links": { - "Homepage": "https://iotex.io" - }, - "marketcap_usd": 0, - "name": "IoTeX Network", - "shortcut": "IOTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:IPOS": { - "links": { - "Homepage": "https://iposlab.com" - }, - "marketcap_usd": 0, - "name": "IPOS Network", - "shortcut": "IPOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ISLM": { - "links": { - "Homepage": "https://islamiccoin.net" - }, - "marketcap_usd": 0, - "name": "Haqq Network", - "shortcut": "ISLM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:IVAR": { - "links": { - "Homepage": "https://ivarex.com" - }, - "marketcap_usd": 0, - "name": "IVAR Chain", - "shortcut": "IVAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:J": { - "links": { - "Homepage": "https://j.blockcoach.com:8089" - }, - "marketcap_usd": 0, - "name": "Metacodechain", - "shortcut": "J", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:JBC": { - "links": { - "Homepage": "https://jibchain.net" - }, - "marketcap_usd": 0, - "name": "JIBCHAIN L1", - "shortcut": "JBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:JEWEL:53935": { - "links": { - "Homepage": "https://defikingdoms.com" - }, - "marketcap_usd": 0, - "name": "DFK Chain", - "shortcut": "JEWEL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:JINDA": { - "links": { - "Homepage": "https://blockchain.or.th" - }, - "marketcap_usd": 0, - "name": "TBSI", - "shortcut": "JINDA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:JOYS": { - "links": { - "Homepage": "https://joys.digital" - }, - "marketcap_usd": 0, - "name": "Joys Digital", - "shortcut": "JOYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KAI": { - "links": { - "Homepage": "https://kardiachain.io" - }, - "marketcap_usd": 28444438, - "name": "KardiaChain", - "shortcut": "KAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KAR": { - "links": { - "Homepage": "https://karura.network" - }, - "marketcap_usd": 0, - "name": "Karura Network", - "shortcut": "KAR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KAVA": { - "links": { - "Homepage": "https://www.kava.io" - }, - "marketcap_usd": 367913718, - "name": "Kava EVM", - "shortcut": "KAVA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KCS": { - "links": { - "Homepage": "https://kcc.io" - }, - "marketcap_usd": 0, - "name": "KCC", - "shortcut": "KCS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KEK": { - "links": { - "Homepage": "https://kekchain.com" - }, - "marketcap_usd": 0, - "name": "Kekchain", - "shortcut": "KEK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KLAY": { - "links": { - "Homepage": "https://www.klaytn.com/" - }, - "marketcap_usd": 890666429, - "name": "Klaytn", - "shortcut": "KLAY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KSX": { - "links": { - "Homepage": "https://sherpax.io/" - }, - "marketcap_usd": 0, - "name": "Sherpax", - "shortcut": "KSX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KTO:2559": { - "links": { - "Homepage": "https://www.kortho.io/" - }, - "marketcap_usd": 0, - "name": "Kortho", - "shortcut": "KTO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:KUB": { - "links": { - "Homepage": "https://www.bitkubchain.com/" - }, - "marketcap_usd": 0, - "name": "Bitkub Chain", - "shortcut": "KUB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:L1": { - "links": { - "Homepage": "https://www.genesisl1.com" - }, - "marketcap_usd": 0, - "name": "Genesis L1", - "shortcut": "L1", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:L99": { - "links": { - "Homepage": "https://luckynetwork.org" - }, - "marketcap_usd": 0, - "name": "Lucky Network", - "shortcut": "L99", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LA": { - "links": { - "Homepage": "https://lachain.io" - }, - "marketcap_usd": 0, - "name": "LACHAIN", - "shortcut": "LA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LAVA": { - "links": { - "Homepage": "https://elysiumscan.vulcanforged.com" - }, - "marketcap_usd": 0, - "name": "Elysium", - "shortcut": "LAVA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LISINS": { - "links": { - "Homepage": "https://lisinski.online" - }, - "marketcap_usd": 0, - "name": "Lisinski", - "shortcut": "LISINS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LUCID": { - "links": { - "Homepage": "https://lucidcoin.io" - }, - "marketcap_usd": 0, - "name": "Lucid Blockchain", - "shortcut": "LUCID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LUDAN": { - "links": { - "Homepage": "https://www.ludan.org/" - }, - "marketcap_usd": 0, - "name": "LUDAN", - "shortcut": "LUDAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:LYC": { - "links": { - "Homepage": "https://lycanchain.com" - }, - "marketcap_usd": 0, - "name": "Lycan Chain", - "shortcut": "LYC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MAI": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "maistestsubnet", - "shortcut": "MAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MAP": { - "links": { - "Homepage": "https://maplabs.io" - }, - "marketcap_usd": 0, - "name": "MAP", - "shortcut": "MAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MARO": { - "links": { - "Homepage": "https://ma.ro/" - }, - "marketcap_usd": 27306090, - "name": "MARO Blockchain", - "shortcut": "MARO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MAS": { - "links": { - "Homepage": "https://masterbank.org" - }, - "marketcap_usd": 0, - "name": "Mas", - "shortcut": "MAS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MATH": { - "links": { - "Homepage": "https://mathchain.org" - }, - "marketcap_usd": 17614958, - "name": "MathChain", - "shortcut": "MATH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MATIC": { - "links": { - "Homepage": "https://polygon.technology/" - }, - "marketcap_usd": 10673372779, - "name": "Polygon", - "shortcut": "MATIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MEER": { - "links": { - "Homepage": "https://github.com/Qitmeer" - }, - "marketcap_usd": 0, - "name": "Qitmeer", - "shortcut": "MEER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:META": { - "links": { - "Homepage": "https://metadium.com" - }, - "marketcap_usd": 61668315, - "name": "Metadium", - "shortcut": "META", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:METAD": { - "links": { - "Homepage": "https://docs.metaplayer.one/" - }, - "marketcap_usd": 0, - "name": "Metaplayerone", - "shortcut": "METAD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:METIS": { - "links": { - "Homepage": "https://www.metis.io" - }, - "marketcap_usd": 0, - "name": "Metis Andromeda", - "shortcut": "METIS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MINTME": { - "links": { - "Homepage": "https://www.mintme.com" - }, - "marketcap_usd": 0, - "name": "MintMe.com Coin", - "shortcut": "MINTME", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MIX": { - "links": { - "Homepage": "https://mix-blockchain.org" - }, - "marketcap_usd": 0, - "name": "Mix", - "shortcut": "MIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MMT": { - "links": { - "Homepage": "https://mmtchain.io/" - }, - "marketcap_usd": 0, - "name": "Mammoth", - "shortcut": "MMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MOLE": { - "links": { - "Homepage": "https://github.com/Jdubedition/molereum" - }, - "marketcap_usd": 0, - "name": "Molereum Network", - "shortcut": "MOLE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MOVR": { - "links": { - "Homepage": "https://moonbeam.network/networks/moonriver/" - }, - "marketcap_usd": 63677633, - "name": "Moonriver", - "shortcut": "MOVR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MTR": { - "links": { - "Homepage": "https://www.meter.io" - }, - "marketcap_usd": 0, - "name": "Meter", - "shortcut": "MTR", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MTT": { - "links": { - "Homepage": "https://metadot.network" - }, - "marketcap_usd": 0, - "name": "MetaDot", - "shortcut": "MTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MTV": { - "links": { - "Homepage": "https://mtv.ac" - }, - "marketcap_usd": 4779941, - "name": "MultiVAC", - "shortcut": "MTV", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MUSIC": { - "links": { - "Homepage": "https://musicoin.tw" - }, - "marketcap_usd": 0, - "name": "Musicoin", - "shortcut": "MUSIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:MYTH": { - "links": { - "Homepage": "https://mythicalgames.com/" - }, - "marketcap_usd": 0, - "name": "Mythical Chain", - "shortcut": "MYTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NEON:245022934": { - "links": { - "Homepage": "https://neon-labs.org" - }, - "marketcap_usd": 0, - "name": "Neon EVM", - "shortcut": "NEON", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NEW": { - "links": { - "Homepage": "https://www.newtonproject.org/" - }, - "marketcap_usd": 3728171, - "name": "Newton", - "shortcut": "NEW", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NRG": { - "links": { - "Homepage": "https://www.energi.world/" - }, - "marketcap_usd": 12197414, - "name": "Energi", - "shortcut": "NRG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NTT": { - "links": { - "Homepage": "https://ntity.io" - }, - "marketcap_usd": 0, - "name": "Ntity", - "shortcut": "NTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NULS": { - "links": { - "Homepage": "https://nuls.io" - }, - "marketcap_usd": 27852400, - "name": "ENULS", - "shortcut": "NULS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NUM": { - "links": { - "Homepage": "https://numbersprotocol.io" - }, - "marketcap_usd": 0, - "name": "Numbers", - "shortcut": "NUM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:NetZ": { - "links": { - "Homepage": "https://mainnetz.io" - }, - "marketcap_usd": 0, - "name": "MainnetZ", - "shortcut": "NetZ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OAC": { - "links": { - "Homepage": "https://scan.oasischain.io" - }, - "marketcap_usd": 0, - "name": "OasisChain", - "shortcut": "OAC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OCTA": { - "links": { - "Homepage": "https://octa.space" - }, - "marketcap_usd": 0, - "name": "OctaSpace", - "shortcut": "OCTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OHO": { - "links": { - "Homepage": "https://oho.ai" - }, - "marketcap_usd": 0, - "name": "OHO", - "shortcut": "OHO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OKT": { - "links": { - "Homepage": "https://www.okex.com/okc" - }, - "marketcap_usd": 0, - "name": "OKXChain", - "shortcut": "OKT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OLO": { - "links": { - "Homepage": "https://ibdt.io" - }, - "marketcap_usd": 0, - "name": "TOOL Global", - "shortcut": "OLO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OLT": { - "links": { - "Homepage": "https://oneledger.io" - }, - "marketcap_usd": 2321403, - "name": "OneLedger", - "shortcut": "OLT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OM": { - "links": { - "Homepage": "https://omplatform.com/" - }, - "marketcap_usd": 0, - "name": "OM Platform", - "shortcut": "OM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OMAX": { - "links": { - "Homepage": "https://www.omaxcoin.com/" - }, - "marketcap_usd": 0, - "name": "Omax", - "shortcut": "OMAX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OMC": { - "links": { - "Homepage": "https://omchain.io" - }, - "marketcap_usd": 2203543, - "name": "omChain", - "shortcut": "OMC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONE:1666600000": { - "links": { - "Homepage": "https://www.harmony.one/" - }, - "marketcap_usd": 283158162, - "name": "Harmony", - "shortcut": "ONE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONE:1666600001": { - "links": { - "Homepage": "https://www.harmony.one/" - }, - "marketcap_usd": 283158162, - "name": "Harmony", - "shortcut": "ONE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONE:1666600002": { - "links": { - "Homepage": "https://www.harmony.one/" - }, - "marketcap_usd": 283158162, - "name": "Harmony", - "shortcut": "ONE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONE:1666600003": { - "links": { - "Homepage": "https://www.harmony.one/" - }, - "marketcap_usd": 283158162, - "name": "Harmony", - "shortcut": "ONE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONG": { - "links": { - "Homepage": "https://ont.io/" - }, - "marketcap_usd": 220559219, - "name": "Ontology", - "shortcut": "ONG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ONUS": { - "links": { - "Homepage": "https://onuschain.io" - }, - "marketcap_usd": 42435453, - "name": "ONUS Chain", - "shortcut": "ONUS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OPC": { - "links": { - "Homepage": "https://www.openchain.live" - }, - "marketcap_usd": 0, - "name": "OpenChain", - "shortcut": "OPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OPN": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "Susono", - "shortcut": "OPN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ORL": { - "links": { - "Homepage": "https://orlchain.com" - }, - "marketcap_usd": 0, - "name": "Orlando Chain", - "shortcut": "ORL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OTP": { - "links": { - "Homepage": "https://parachain.origintrail.io" - }, - "marketcap_usd": 0, - "name": "OriginTrail Parachain", - "shortcut": "OTP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OXYN": { - "links": { - "Homepage": "https://beta.opulent-x.com" - }, - "marketcap_usd": 0, - "name": "Opulent-X BETA", - "shortcut": "OXYN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:OY": { - "links": { - "Homepage": "https://www.oychain.io" - }, - "marketcap_usd": 0, - "name": "OYchain", - "shortcut": "OY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PALM": { - "links": { - "Homepage": "https://palm.io" - }, - "marketcap_usd": 0, - "name": "Palm", - "shortcut": "PALM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PDC": { - "links": { - "Homepage": "https://ipdc.io" - }, - "marketcap_usd": 0, - "name": "PDC", - "shortcut": "PDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PETH": { - "links": { - "Homepage": "https://primusmoney.com" - }, - "marketcap_usd": 0, - "name": "PrimusChain", - "shortcut": "PETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PFT:909": { - "links": { - "Homepage": "https://portalfantasy.io" - }, - "marketcap_usd": 0, - "name": "Portal Fantasy Chain", - "shortcut": "PFT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PHT": { - "links": { - "Homepage": "https://explorer.lightstreams.io" - }, - "marketcap_usd": 0, - "name": "Lightstreams", - "shortcut": "PHT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PHX": { - "links": { - "Homepage": "https://cryptophoenix.org/phoenix" - }, - "marketcap_usd": 0, - "name": "Phoenix", - "shortcut": "PHX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PIRL": { - "links": { - "Homepage": "https://pirl.io" - }, - "marketcap_usd": 0, - "name": "Pirl", - "shortcut": "PIRL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PIX": { - "links": { - "Homepage": "https://chain.pixie.xyz" - }, - "marketcap_usd": 0, - "name": "Pixie Chain", - "shortcut": "PIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PLQ": { - "links": { - "Homepage": "https://planq.network" - }, - "marketcap_usd": 0, - "name": "Planq", - "shortcut": "PLQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PLS": { - "links": { - "Homepage": "https://pulsechain.com/" - }, - "marketcap_usd": 0, - "name": "PulseChain", - "shortcut": "PLS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:POA": { - "links": { - "Homepage": "https://poa.network" - }, - "marketcap_usd": 8185146, - "name": "POA Network Core", - "shortcut": "POA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:POLIS": { - "links": { - "Homepage": "https://polis.tech" - }, - "marketcap_usd": 92704, - "name": "Polis", - "shortcut": "POLIS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:POM": { - "links": { - "Homepage": "https://proofofmemes.org" - }, - "marketcap_usd": 0, - "name": "Proof Of Memes", - "shortcut": "POM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:POP": { - "links": { - "Homepage": "https://popcateum.org" - }, - "marketcap_usd": 0, - "name": "Popcateum", - "shortcut": "POP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PRB": { - "links": { - "Homepage": "https://net.paribu.com" - }, - "marketcap_usd": 0, - "name": "Paribu Net", - "shortcut": "PRB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PSC": { - "links": { - "Homepage": "https://www.polysmartchain.com/" - }, - "marketcap_usd": 0, - "name": "PolySmartChain", - "shortcut": "PSC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:PTX": { - "links": { - "Homepage": "https://www.pandoproject.org/" - }, - "marketcap_usd": 0, - "name": "PandoProject", - "shortcut": "PTX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QDC": { - "links": { - "Homepage": "https://quadrans.io" - }, - "marketcap_usd": 0, - "name": "Quadrans Blockchain", - "shortcut": "QDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKA": { - "links": { - "Homepage": "https://qkacoin.org" - }, - "marketcap_usd": 0, - "name": "Quokkacoin", - "shortcut": "QKA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100000": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100001": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100002": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100003": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100004": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100005": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100006": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100007": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKC:100008": { - "links": { - "Homepage": "https://www.quarkchain.io" - }, - "marketcap_usd": 74074939, - "name": "QuarkChain", - "shortcut": "QKC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QKI": { - "links": { - "Homepage": "https://quarkblockchain.org/" - }, - "marketcap_usd": 0, - "name": "quarkblockchain", - "shortcut": "QKI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:QOM": { - "links": { - "Homepage": "https://qom.one" - }, - "marketcap_usd": 0, - "name": "QL1", - "shortcut": "QOM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RBD": { - "links": { - "Homepage": "https://www.wegochain.io" - }, - "marketcap_usd": 0, - "name": "Wegochain Rubidium", - "shortcut": "RBD", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RBTC": { - "links": { - "Homepage": "https://rsk.co" - }, - "marketcap_usd": 0, - "name": "RSK", - "shortcut": "RBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:REAL": { - "links": { - "Homepage": "https://www.rclsidechain.com/" - }, - "marketcap_usd": 0, - "name": "Realchain", - "shortcut": "REAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:REDLC": { - "links": { - "Homepage": "https://redlight.finance/" - }, - "marketcap_usd": 0, - "name": "Redlight Chain", - "shortcut": "REDLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:REI:47805": { - "links": { - "Homepage": "https://rei.network/" - }, - "marketcap_usd": 32752198, - "name": "REI Network", - "shortcut": "REI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RESIN": { - "links": { - "Homepage": "https://resincoin.dev" - }, - "marketcap_usd": 0, - "name": "ResinCoin", - "shortcut": "RESIN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RING": { - "links": { - "Homepage": "https://darwinia.network/" - }, - "marketcap_usd": 7420230, - "name": "Darwinia Network", - "shortcut": "RING", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RNA": { - "links": { - "Homepage": "https://scan.genechain.io/" - }, - "marketcap_usd": 0, - "name": "GeneChain", - "shortcut": "RNA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ROC:1288": { - "links": { - "Homepage": "https://docs.moonbeam.network/learn/platform/networks/overview/" - }, - "marketcap_usd": 0, - "name": "Moonrock", - "shortcut": "ROC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RPG": { - "links": { - "Homepage": "https://rangersprotocol.com" - }, - "marketcap_usd": 1063873, - "name": "Rangers Protocol", - "shortcut": "RPG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:RUPX": { - "links": { - "Homepage": "https://www.rupx.io" - }, - "marketcap_usd": 0, - "name": "Rupaya", - "shortcut": "RUPX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SAMA": { - "links": { - "Homepage": "https://moonsama.com" - }, - "marketcap_usd": 0, - "name": "Exosama Network", - "shortcut": "SAMA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SDN": { - "links": { - "Homepage": "https://shiden.astar.network/" - }, - "marketcap_usd": 0, - "name": "Shiden", - "shortcut": "SDN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SEED": { - "links": { - "Homepage": "https://www.seedcoin.network/" - }, - "marketcap_usd": 0, - "name": "SeedCoin-Network", - "shortcut": "SEED", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SETM": { - "links": { - "Homepage": "https://setheum.xyz" - }, - "marketcap_usd": 0, - "name": "Setheum", - "shortcut": "SETM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SFL": { - "links": { - "Homepage": "https://hupayx.io" - }, - "marketcap_usd": 0, - "name": "Taycan", - "shortcut": "SFL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SGB": { - "links": { - "Homepage": "https://flare.xyz" - }, - "marketcap_usd": 0, - "name": "Songbird Canary-Network", - "shortcut": "SGB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SHIB": { - "links": { - "Homepage": "https://www.shibachain.net" - }, - "marketcap_usd": 0, - "name": "ShibaChain", - "shortcut": "SHIB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SINSO": { - "links": { - "Homepage": "https://sinso.io" - }, - "marketcap_usd": 0, - "name": "AmStar", - "shortcut": "SINSO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SKU": { - "links": { - "Homepage": "https://clover.finance/sakura" - }, - "marketcap_usd": 687504, - "name": "Sakura", - "shortcut": "SKU", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SMT": { - "links": { - "Homepage": "https://smartmesh.io" - }, - "marketcap_usd": 2755986, - "name": "SmartMesh", - "shortcut": "SMT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SNT": { - "links": { - "Homepage": "https://novanetwork.io" - }, - "marketcap_usd": 0, - "name": "Nova Network", - "shortcut": "SNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SOTER:68": { - "links": { - "Homepage": "https://www.soterone.com" - }, - "marketcap_usd": 0, - "name": "SoterOne", - "shortcut": "SOTER", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SPARK": { - "links": { - "Homepage": "https://docs.fuse.io/general/fuse-network-blockchain/fuse-testnet" - }, - "marketcap_usd": 0, - "name": "Fuse Sparknet", - "shortcut": "SPARK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SPOA": { - "links": { - "Homepage": "https://poa.network" - }, - "marketcap_usd": 0, - "name": "POA Network Sokol", - "shortcut": "SPOA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SRDX": { - "links": { - "Homepage": "https://mysardis.com" - }, - "marketcap_usd": 0, - "name": "Sardis", - "shortcut": "SRDX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SRN": { - "links": { - "Homepage": "https://surnet.org" - }, - "marketcap_usd": 0, - "name": "SUR Blockchain Network", - "shortcut": "SRN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:STAND": { - "links": { - "Homepage": "https://goldsmartchain.com" - }, - "marketcap_usd": 0, - "name": "Gold Smart Chain", - "shortcut": "STAND", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:STOS": { - "links": { - "Homepage": "https://www.thestratos.org" - }, - "marketcap_usd": 13276679, - "name": "Stratos", - "shortcut": "STOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SVRN": { - "links": { - "Homepage": "https://soverun.com" - }, - "marketcap_usd": 0, - "name": "Soverun", - "shortcut": "SVRN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SX": { - "links": { - "Homepage": "https://www.sx.technology" - }, - "marketcap_usd": 0, - "name": "SX Network", - "shortcut": "SX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:Seele": { - "links": { - "Homepage": "https://seelen.pro/" - }, - "marketcap_usd": 3511278, - "name": "Seele", - "shortcut": "Seele", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:SmuX": { - "links": { - "Homepage": "https://www.streamux.cloud" - }, - "marketcap_usd": 0, - "name": "StreamuX Blockchain", - "shortcut": "SmuX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:T-EKTA": { - "links": { - "Homepage": "https://www.ekta.io" - }, - "marketcap_usd": 0, - "name": "T-EKTA", - "shortcut": "T-EKTA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TAO": { - "links": { - "Homepage": "https://tao.network" - }, - "marketcap_usd": 0, - "name": "Tao Network", - "shortcut": "TAO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TBG": { - "links": { - "Homepage": "https://tbwg.io" - }, - "marketcap_usd": 0, - "name": "TBWG Chain", - "shortcut": "TBG", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TCH": { - "links": { - "Homepage": "https://thaichain.io" - }, - "marketcap_usd": 0, - "name": "ThaiChain", - "shortcut": "TCH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TELE:8000": { - "links": { - "Homepage": "https://teleport.network" - }, - "marketcap_usd": 0, - "name": "Teleport", - "shortcut": "TELE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TFI": { - "links": { - "Homepage": "https://exp.thaifi.com" - }, - "marketcap_usd": 0, - "name": "ThaiChain 2.0 ThaiFi", - "shortcut": "TFI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TLC": { - "links": { - "Homepage": "https://tlchain.network/" - }, - "marketcap_usd": 0, - "name": "TLChain Network", - "shortcut": "TLC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TLOS:40": { - "links": { - "Homepage": "https://telos.net" - }, - "marketcap_usd": 0, - "name": "Telos EVM", - "shortcut": "TLOS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TMY": { - "links": { - "Homepage": "https://tmychain.org/" - }, - "marketcap_usd": 0, - "name": "TMY Chain", - "shortcut": "TMY", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TOMB": { - "links": { - "Homepage": "https://tombchain.com/" - }, - "marketcap_usd": 0, - "name": "Tomb Chain", - "shortcut": "TOMB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TOMO:88": { - "links": { - "Homepage": "https://tomochain.com" - }, - "marketcap_usd": 40653633, - "name": "TomoChain", - "shortcut": "TOMO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TOYS": { - "links": { - "Homepage": "https://joys.digital" - }, - "marketcap_usd": 0, - "name": "Joys Digital TestNet", - "shortcut": "TOYS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TPC": { - "links": { - "Homepage": "https://techpay.io/" - }, - "marketcap_usd": 0, - "name": "TechPay", - "shortcut": "TPC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TPEP": { - "links": { - "Homepage": "https://pepchain.io" - }, - "marketcap_usd": 0, - "name": "PepChain Churchill", - "shortcut": "TPEP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TSF": { - "links": { - "Homepage": "https://teslafunds.io" - }, - "marketcap_usd": 0, - "name": "Teslafunds", - "shortcut": "TSF", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TT": { - "links": { - "Homepage": "https://thundercore.com" - }, - "marketcap_usd": 53233013, - "name": "ThunderCore", - "shortcut": "TT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TWL": { - "links": { - "Homepage": "https://twala.io/" - }, - "marketcap_usd": 0, - "name": "Jellie", - "shortcut": "TWL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TXDC": { - "links": { - "Homepage": "https://xinfin.org" - }, - "marketcap_usd": 0, - "name": "XDC Apothem Network", - "shortcut": "TXDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:TXL": { - "links": { - "Homepage": "https://autobahn.network" - }, - "marketcap_usd": 0, - "name": "Autobahn Network", - "shortcut": "TXL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:U+25B3": { - "links": { - "Homepage": "https://bloxberg.org" - }, - "marketcap_usd": 0, - "name": "bloxberg", - "shortcut": "U+25B3", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:UBC": { - "links": { - "Homepage": "https://www.ubchain.site/" - }, - "marketcap_usd": 0, - "name": "UB Smart Chain", - "shortcut": "UBC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:UBQ": { - "links": { - "Homepage": "https://ubiqsmart.com" - }, - "marketcap_usd": 1302549, - "name": "Ubiq", - "shortcut": "UBQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ULX": { - "links": { - "Homepage": "https://ultron.foundation" - }, - "marketcap_usd": 0, - "name": "Ultron", - "shortcut": "ULX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:UNQ": { - "links": { - "Homepage": "https://unique.network" - }, - "marketcap_usd": 0, - "name": "Unique", - "shortcut": "UNQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:UZMI": { - "links": { - "Homepage": "https://uzmigames.com.br/" - }, - "marketcap_usd": 0, - "name": "Uzmi Network", - "shortcut": "UZMI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VAL": { - "links": { - "Homepage": "https://valorbit.com" - }, - "marketcap_usd": 0, - "name": "Valorbit", - "shortcut": "VAL", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VET": { - "links": { - "Homepage": "https://vechain.org" - }, - "marketcap_usd": 2002440234, - "name": "VeChain", - "shortcut": "VET", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VETH": { - "links": { - "Homepage": "https://www.openvessel.io" - }, - "marketcap_usd": 0, - "name": "OpenVessel", - "shortcut": "VETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VLX": { - "links": { - "Homepage": "https://velas.com" - }, - "marketcap_usd": 0, - "name": "Velas EVM", - "shortcut": "VLX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VNDT": { - "links": { - "Homepage": "https://bo.vcex.xyz/" - }, - "marketcap_usd": 0, - "name": "VChain", - "shortcut": "VNDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VNT": { - "links": { - "Homepage": "https://ventionscan.io" - }, - "marketcap_usd": 0, - "name": "Vention Smart Chain", - "shortcut": "VNT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VS:888888": { - "links": { - "Homepage": "https://www.v.network" - }, - "marketcap_usd": 0, - "name": "Vision -", - "shortcut": "VS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:VSC": { - "links": { - "Homepage": "https://vsc-dataseed.vyvo.org" - }, - "marketcap_usd": 0, - "name": "Vyvo Smart Chain", - "shortcut": "VSC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:W3G": { - "links": { - "Homepage": "https://web3games.org/" - }, - "marketcap_usd": 0, - "name": "Web3Games Devnet", - "shortcut": "W3G", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:W3Q:333": { - "links": { - "Homepage": "https://web3q.io/home.w3q/" - }, - "marketcap_usd": 0, - "name": "Web3Q", - "shortcut": "W3Q", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:WAN": { - "links": { - "Homepage": "https://www.wanscan.org" - }, - "marketcap_usd": 58286398, - "name": "Wanchain", - "shortcut": "WAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - }, - { - "name": "Wanchain Wallet", - "url": "https://www.wanchain.org/getstarted/" - } - ] - }, - "eth:WEB": { - "links": { - "Homepage": "https://webchain.network" - }, - "marketcap_usd": 0, - "name": "Webchain", - "shortcut": "WEB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:WEMIX": { - "links": { - "Homepage": "https://wemix.com" - }, - "marketcap_usd": 525753922, - "name": "WEMIX3.0", - "shortcut": "WEMIX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:WGM": { - "links": { - "Homepage": "https://subnets-test.avax.network/wagmi/details" - }, - "marketcap_usd": 0, - "name": "WAGMI", - "shortcut": "WGM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:WTT": { - "links": { - "Homepage": "http://www.cadaut.com" - }, - "marketcap_usd": 0, - "name": "World Trade Technical Chain", - "shortcut": "WTT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XDC": { - "links": { - "Homepage": "https://xinfin.org" - }, - "marketcap_usd": 0, - "name": "XinFin XDC Network", - "shortcut": "XDC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "XDC Wallet", - "url": "https://wallet.xinfin.network" - } - ] - }, - "eth:XERO": { - "links": { - "Homepage": "https://xerom.org" - }, - "marketcap_usd": 0, - "name": "Xerom", - "shortcut": "XERO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XETA": { - "links": { - "Homepage": "https://xanachain.xana.net/" - }, - "marketcap_usd": 0, - "name": "XANAChain", - "shortcut": "XETA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XODEX": { - "links": { - "Homepage": "https://xo-dex.com" - }, - "marketcap_usd": 0, - "name": "XODEX", - "shortcut": "XODEX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XT": { - "links": { - "Homepage": "https://xsc.pub/" - }, - "marketcap_usd": 0, - "name": "XT Smart Chain", - "shortcut": "XT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XVM": { - "links": { - "Homepage": "https://venidium.io" - }, - "marketcap_usd": 0, - "name": "Venidium", - "shortcut": "XVM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:XZO": { - "links": { - "Homepage": "https://exzo.network" - }, - "marketcap_usd": 0, - "name": "Exzo Network", - "shortcut": "XZO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:YCC": { - "links": { - "Homepage": "https://www.yuan.org" - }, - "marketcap_usd": 0, - "name": "YuanChain", - "shortcut": "YCC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:YETI": { - "links": { - "Homepage": "https://nepalblockchain.network" - }, - "marketcap_usd": 0, - "name": "Nepal Blockchain Network", - "shortcut": "YETI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZENIQ": { - "links": { - "Homepage": "https://www.zeniq.dev/" - }, - "marketcap_usd": 0, - "name": "Zeniq", - "shortcut": "ZENIQ", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZENITH": { - "links": { - "Homepage": "https://www.zenithchain.co/" - }, - "marketcap_usd": 0, - "name": "Zenith", - "shortcut": "ZENITH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZERO": { - "links": { - "Homepage": "https://www.singularity.gold" - }, - "marketcap_usd": 84248, - "name": "Singularity ZERO", - "shortcut": "ZERO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZETA": { - "links": { - "Homepage": "https://docs.zetachain.com/" - }, - "marketcap_usd": 0, - "name": "ZetaChain", - "shortcut": "ZETA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZTH:427": { - "links": { - "Homepage": "" - }, - "marketcap_usd": 0, - "name": "Zeeth Chain", - "shortcut": "ZTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:ZYX": { - "links": { - "Homepage": "https://zyx.network/" - }, - "marketcap_usd": 0, - "name": "Zyx", - "shortcut": "ZYX", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:atp": { - "links": { - "Homepage": "https://www.alaya.network/" - }, - "marketcap_usd": 0, - "name": "Alaya", - "shortcut": "atp", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:cTH": { - "links": { - "Homepage": "https://cheapeth.org/" - }, - "marketcap_usd": 0, - "name": "cheapETH", - "shortcut": "cTH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:cet": { - "links": { - "Homepage": "https://www.coinex.org/" - }, - "marketcap_usd": 0, - "name": "CoinEx Smart Chain", - "shortcut": "cet", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:eBTC": { - "links": { - "Homepage": "https://bitcoinevm.com" - }, - "marketcap_usd": 0, - "name": "Bitcoin EVM", - "shortcut": "eBTC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:hP2": { - "links": { - "Homepage": "https://p12.network" - }, - "marketcap_usd": 0, - "name": "P12 Chain", - "shortcut": "hP2", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:jfin": { - "links": { - "Homepage": "https://jfinchain.com" - }, - "marketcap_usd": 0, - "name": "JFIN Chain", - "shortcut": "jfin", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:lat": { - "links": { - "Homepage": "https://www.platon.network" - }, - "marketcap_usd": 78424786, - "name": "PlatON", - "shortcut": "lat", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:mADA": { - "links": { - "Homepage": "https://milkomeda.com" - }, - "marketcap_usd": 0, - "name": "Milkomeda C1", - "shortcut": "mADA", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:mALGO": { - "links": { - "Homepage": "https://milkomeda.com" - }, - "marketcap_usd": 0, - "name": "Milkomeda A1", - "shortcut": "mALGO", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:mc": { - "links": { - "Homepage": "https://moac.io" - }, - "marketcap_usd": 0, - "name": "MOAC", - "shortcut": "mc", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:nSAN": { - "links": { - "Homepage": "https://sanr.app" - }, - "marketcap_usd": 0, - "name": "SanR Chain", - "shortcut": "nSAN", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:pCKB": { - "links": { - "Homepage": "https://www.nervos.org" - }, - "marketcap_usd": 0, - "name": "Godwoken", - "shortcut": "pCKB", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:peggle": { - "links": { - "Homepage": "https://teampeggle.com" - }, - "marketcap_usd": 0, - "name": "pegglecoin", - "shortcut": "peggle", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tBVE": { - "links": { - "Homepage": "https://beverlyhills.ethdevops.io" - }, - "marketcap_usd": 0, - "name": "Beverly Hills", - "shortcut": "tBVE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tCRC": { - "links": { - "Homepage": "https://github.com/ethereum-pocr/kerleano" - }, - "marketcap_usd": 0, - "name": "Kerleano", - "shortcut": "tCRC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tETH:11155111": { - "links": { - "Homepage": "https://sepolia.otterscan.io" - }, - "marketcap_usd": 0, - "name": "Sepolia", - "shortcut": "tETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tETH:3": { - "links": { - "Homepage": "https://github.com/ethereum/ropsten" - }, - "marketcap_usd": 0, - "name": "Ropsten", - "shortcut": "tETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tETH:4": { - "links": { - "Homepage": "https://www.rinkeby.io" - }, - "marketcap_usd": 0, - "name": "Rinkeby", - "shortcut": "tETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tETH:42": { - "links": { - "Homepage": "https://kovan-testnet.github.io/website" - }, - "marketcap_usd": 0, - "name": "Kovan", - "shortcut": "tETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tETH:5": { - "links": { - "Homepage": "https://goerli.net/#about" - }, - "marketcap_usd": 0, - "name": "Goerli", - "shortcut": "tETH", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tKEK": { - "links": { - "Homepage": "https://kekchain.com" - }, - "marketcap_usd": 0, - "name": "Kekchain (kektest)", - "shortcut": "tKEK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tMAP": { - "links": { - "Homepage": "https://maplabs.io" - }, - "marketcap_usd": 0, - "name": "MAP Makalu", - "shortcut": "tMAP", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tMATIC": { - "links": { - "Homepage": "https://polygon.technology/" - }, - "marketcap_usd": 0, - "name": "Mumbai", - "shortcut": "tMATIC", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:tWIRE": { - "links": { - "Homepage": "https://wireshape.org" - }, - "marketcap_usd": 0, - "name": "Floripa", - "shortcut": "tWIRE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:taro": { - "links": { - "Homepage": "https://j2o.io" - }, - "marketcap_usd": 0, - "name": "J2O Taro", - "shortcut": "taro", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:xDAI:100": { - "links": { - "Homepage": "https://docs.gnosischain.com" - }, - "marketcap_usd": 6301880, - "name": "Gnosis", - "shortcut": "xDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:xDAI:300": { - "links": { - "Homepage": "https://www.xdaichain.com/for-developers/optimism-optimistic-rollups-on-gc" - }, - "marketcap_usd": 6301880, - "name": "Optimism on Gnosis", - "shortcut": "xDAI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:xlon": { - "links": { - "Homepage": "https://xlon.org" - }, - "marketcap_usd": 0, - "name": "Excelon", - "shortcut": "xlon", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "eth:\u25c8": { - "links": { - "Homepage": "https://crystaleum.org" - }, - "marketcap_usd": 0, - "name": "Crystaleum", - "shortcut": "\u25c8", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "MyCrypto", - "url": "https://mycrypto.com" - }, - { - "name": "MyEtherWallet", - "url": "https://www.myetherwallet.com" - } - ] - }, - "misc:ADA": { - "links": { - "Github": "https://github.com/input-output-hk/cardano-node", - "Homepage": "https://www.cardano.org" - }, - "marketcap_usd": 12578496280, - "name": "Cardano", - "shortcut": "ADA", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - } - ] - }, - "misc:BNB": { - "links": { - "Homepage": "https://binance.org" - }, - "marketcap_usd": 47729156144, - "name": "Binance Chain", - "shortcut": "BNB", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Binance Wallet", - "url": "https://binance.org/unlock" - } - ] - }, - "misc:EOS": { - "links": { - "Github": "https://github.com/EOSIO/eos", - "Homepage": "https://eos.io" - }, - "marketcap_usd": 1253975568, - "name": "EOS", - "shortcut": "EOS", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Bloks.io", - "url": "https://bloks.io/wallet" - } - ] - }, - "misc:MAID": { - "links": { - "Github": "https://github.com/maidsafe", - "Homepage": "https://maidsafe.net" - }, - "marketcap_usd": 58807837, - "name": "MaidSafeCoin", - "shortcut": "MAID", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [] - }, - "misc:OMNI": { - "links": { - "Github": "https://github.com/OmniLayer", - "Homepage": "https://www.omnilayer.org" - }, - "marketcap_usd": 551822, - "name": "Omni", - "shortcut": "OMNI", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [] - }, - "misc:USDT": { - "links": { - "Homepage": "https://tether.to" - }, - "marketcap_usd": 70941600691, - "name": "Tether", - "shortcut": "USDT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [] - }, - "misc:XLM": { - "links": { - "Github": "https://github.com/stellar/stellar-core", - "Homepage": "https://www.stellar.org" - }, - "marketcap_usd": 2316269327, - "name": "Stellar", - "shortcut": "XLM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Account Viewer", - "url": "https://accountviewer.stellar.org/" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - }, - { - "name": "Stellarport", - "url": "https://stellarport.io/" - } - ] - }, - "misc:XMR": { - "links": { - "Github": "https://github.com/monero-project/monero", - "Homepage": "https://getmonero.org" - }, - "marketcap_usd": 2733395377, - "name": "Monero", - "shortcut": "XMR", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Monero CLI/GUI", - "url": "https://www.getmonero.org/downloads/" - } - ] - }, - "misc:XRP": { - "links": { - "Github": "https://github.com/ripple/rippled", - "Homepage": "https://ripple.com" - }, - "marketcap_usd": 19193526787, - "name": "Ripple", - "shortcut": "XRP", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Trezor Suite", - "url": "https://suite.trezor.io" - }, - { - "name": "Exodus", - "url": "https://www.exodus.io" - } - ] - }, - "misc:XTZ": { - "links": { - "Github": "https://github.com/tezos/tezos", - "Homepage": "https://tezos.com" - }, - "marketcap_usd": 1094195402, - "name": "Tezos", - "shortcut": "XTZ", - "t1_enabled": "no", - "t2_enabled": "yes", - "type": "coin", - "wallet": [ - { - "name": "Briskett", - "url": "https://briskett.app" - } - ] - }, - "nem:BREEZE": { - "links": { - "Homepage": "https://breeze.chat" - }, - "marketcap_usd": 0, - "name": "Breeze Token", - "shortcut": "BREEZE", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - }, - "nem:DIM": { - "links": { - "Homepage": "https://www.dimcoin.io" - }, - "marketcap_usd": 0, - "name": "DIMCOIN", - "shortcut": "DIM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - }, - "nem:DIMTOK": { - "coinmarketcap_alias": "dimcoin", - "links": { - "Homepage": "https://www.dimcoin.io" - }, - "marketcap_usd": 0, - "name": "DIM TOKEN", - "shortcut": "DIMTOK", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - }, - "nem:PAC:CHS": { - "links": { - "Homepage": "https://pacnem.com" - }, - "marketcap_usd": 0, - "name": "PacNEM Score Tokens", - "shortcut": "PAC:CHS", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - }, - "nem:PAC:HRT": { - "links": { - "Homepage": "https://pacnem.com" - }, - "marketcap_usd": 0, - "name": "PacNEM Game Credits", - "shortcut": "PAC:HRT", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - }, - "nem:XEM": { - "links": { - "Homepage": "https://nemplatform.com" - }, - "marketcap_usd": 475266269, - "name": "NEM", - "shortcut": "XEM", - "t1_enabled": "yes", - "t2_enabled": "yes", - "type": "mosaic", - "wallet": [ - { - "name": "Nano Wallet", - "url": "https://nemplatform.com/wallets/#desktop" - } - ] - } - }, - "info": { - "marketcap_supported": "103.22 %", - "marketcap_usd": 1102849874078, - "t1_coins": 2106, - "t2_coins": 2112, - "total_marketcap_usd": 1068459286951, - "updated_at": 1677585029, - "updated_at_readable": "Tue Feb 28 12:50:29 2023" - } -} diff --git a/common/defs/duplicity_overrides.json b/common/defs/duplicity_overrides.json index 85b5a11fcc..cfd324d0c6 100644 --- a/common/defs/duplicity_overrides.json +++ b/common/defs/duplicity_overrides.json @@ -3,9 +3,6 @@ "erc20:eth:USDT": false, "eth:BNB:56": false, "eth:MATIC:137": false, - "eth:tETH:3": false, - "eth:tETH:4": false, - "eth:tETH:5": false, "misc:BNB": false, "misc:USDT": false } diff --git a/common/defs/ethereum/networks.json b/common/defs/ethereum/networks.json index 884d4beeb7..f2e00975ea 100644 --- a/common/defs/ethereum/networks.json +++ b/common/defs/ethereum/networks.json @@ -9,35 +9,27 @@ "slip44": 60 }, { - "chain": "rop", - "chain_id": 3, + "chain": "hol", + "chain_id": 17000, "is_testnet": true, - "name": "Ropsten", - "shortcut": "tETH", + "name": "Holesky", + "shortcut": "tHOL", "slip44": 1 }, { - "chain": "rin", - "chain_id": 4, + "chain": "sep", + "chain_id": 11155111, "is_testnet": true, - "name": "Rinkeby", - "shortcut": "tETH", + "name": "Sepolia", + "shortcut": "tSEP", "slip44": 1 }, { - "chain": "gor", - "chain_id": 5, - "is_testnet": true, - "name": "Görli", - "shortcut": "tETH", - "slip44": 1 - }, - { - "chain": "bnb", + "chain": "bsc", "chain_id": 56, "coingecko_id": "binance-smart-chain", "is_testnet": false, - "name": "Binance Smart Chain", + "name": "BNB Smart Chain", "shortcut": "BNB", "slip44": 714 }, @@ -56,7 +48,7 @@ "coingecko_id": "polygon-pos", "is_testnet": false, "name": "Polygon", - "shortcut": "MATIC", + "shortcut": "POL", "slip44": 966 } ] diff --git a/common/defs/ethereum/released-definitions-timestamp.txt b/common/defs/ethereum/released-definitions-timestamp.txt index 576ad74354..aea5282a5b 100644 --- a/common/defs/ethereum/released-definitions-timestamp.txt +++ b/common/defs/ethereum/released-definitions-timestamp.txt @@ -1 +1 @@ -2024-01-03T12:26:50+00:00 +2024-07-09T10:03:06+00:00 diff --git a/common/defs/misc/misc.json b/common/defs/misc/misc.json index f98f4d9114..dbd09766d8 100644 --- a/common/defs/misc/misc.json +++ b/common/defs/misc/misc.json @@ -4,189 +4,104 @@ "shortcut": "LSK", "slip44": 134, "curve": "ed25519", - "decimals": 8, - "links": { - "Homepage": "https://lisk.io/", - "Github": "https://github.com/LiskHQ/lisk" - }, - "wallet": { - "Liskish Wallet": "https://github.com/hirishh/liskish-wallet/releases" - } + "decimals": 8 }, { "name": "Stellar", "slip44": 148, "curve": "ed25519", "shortcut": "XLM", - "decimals": 7, - "links": { - "Homepage": "https://www.stellar.org", - "Github": "https://github.com/stellar/stellar-core" - }, - "wallet": { - "Account Viewer": "https://accountviewer.stellar.org/", - "Exodus": "https://www.exodus.io", - "Stellarport": "https://stellarport.io/" - } + "decimals": 7 }, { "name": "Monero", "shortcut": "XMR", "slip44": 128, "curve": "ed25519", - "decimals": 12, - "links": { - "Homepage": "https://getmonero.org", - "Github": "https://github.com/monero-project/monero" - }, - "wallet": { - "Monero CLI/GUI": "https://www.getmonero.org/downloads/" - } + "decimals": 12 }, { "name": "Ripple", "shortcut": "XRP", "slip44": 144, "curve": "secp256k1", - "decimals": 6, - "links": { - "Homepage": "https://ripple.com", - "Github": "https://github.com/ripple/rippled" - }, - "wallet": { - "Trezor Suite": "https://suite.trezor.io", - "Exodus": "https://www.exodus.io" - } + "decimals": 6 }, { "name": "Ripple Testnet", "shortcut": "tXRP", "slip44": 1, "curve": "secp256k1", - "decimals": 6, - "links": { - "Homepage": "https://ripple.com", - "Github": "https://github.com/ripple/rippled" - }, - "wallet": { - "Trezor Suite": "https://suite.trezor.io" - } + "decimals": 6 }, { "name": "Cardano", "shortcut": "ADA", "slip44": 1815, "curve": "ed25519", - "decimals": 6, - "links": { - "Homepage": "https://www.cardano.org", - "Github": "https://github.com/input-output-hk/cardano-node" - }, - "wallet": { - "Trezor Suite": "https://suite.trezor.io" - } + "decimals": 6 }, { "name": "Cardano Preview Testnet", "shortcut": "tADA", "slip44": 1815, "curve": "ed25519", - "decimals": 6, - "links": { - "Homepage": "https://www.cardano.org", - "Github": "https://github.com/input-output-hk/cardano-node" - }, - "wallet": { - "Trezor Suite": "https://suite.trezor.io" - } + "decimals": 6 }, { "name": "Tezos", "shortcut": "XTZ", "slip44": 1729, "curve": "ed25519", - "decimals": 6, - "links": { - "Homepage": "https://tezos.com", - "Github": "https://github.com/tezos/tezos" - }, - "wallet": { - "Briskett": "https://briskett.app" - } + "decimals": 6 }, { "name": "EOS", "shortcut": "EOS", "slip44": 194, "curve": "secp256k1", - "decimals": 4, - "links": { - "Homepage": "https://eos.io", - "Github": "https://github.com/EOSIO/eos" - }, - "wallet": { - "Bloks.io": "https://bloks.io/wallet" - } + "decimals": 4 }, { "name": "Omni", "shortcut": "OMNI", "slip44": 0, "curve": "secp256k1", - "decimals": 2, - "links": { - "Homepage": "https://www.omnilayer.org", - "Github": "https://github.com/OmniLayer" - }, - "wallet": {} + "decimals": 2 }, { "name": "MaidSafeCoin", "shortcut": "MAID", "slip44": 0, "curve": "secp256k1", - "decimals": 8, - "links": { - "Homepage": "https://maidsafe.net", - "Github": "https://github.com/maidsafe" - }, - "wallet": {} + "decimals": 8 }, { "name": "Binance Chain", "shortcut": "BNB", "slip44": 714, "curve": "secp256k1", - "decimals": 8, - "links": { - "Homepage": "https://binance.org" - }, - "wallet": { - "Binance Wallet": "https://binance.org/unlock" - } + "decimals": 8 }, { "name": "Tether", "shortcut": "USDT", "slip44": 0, "curve": "secp256k1", - "decimals": 2, - "links": { - "Homepage": "https://tether.to" - }, - "wallet": {} + "decimals": 2 }, { "name": "Solana", "shortcut": "SOL", "slip44": 501, "curve": "ed25519", - "decimals": 9, - "links": { - "Homepage": "https://solana.com" - }, - "wallet": { - "Trezor Suite": "https://suite.trezor.io" - } + "decimals": 9 + }, + { + "name": "Solana Devnet", + "shortcut": "DSOL", + "slip44": 501, + "curve": "ed25519", + "decimals": 9 } ] diff --git a/common/defs/solana/programs.json b/common/defs/solana/programs.json index 7f176edc54..1531806d96 100644 --- a/common/defs/solana/programs.json +++ b/common/defs/solana/programs.json @@ -2976,6 +2976,12 @@ "name": "spl_token", "is_authority": false, "optional": false + }, + { + "//": "Some dApps still include the rent sysvar although it's not officially required anymore.", + "name": "rent_sysvar", + "is_authority": false, + "optional": true } ], "ui_properties": [ diff --git a/common/defs/support.json b/common/defs/support.json index ed46cc4ed3..24cb96813f 100644 --- a/common/defs/support.json +++ b/common/defs/support.json @@ -56,36 +56,35 @@ "bitcoin:tRVN": "1.10.0", "bitcoin:tSMART": "1.7.1", "erc20:bnb:ATOM": "1.11.3", - "erc20:eth:AAVE": "1.11.3", + "erc20:eth:AAVE": "1.10.4", "erc20:eth:APE": "1.11.3", - "erc20:eth:AXS": "1.11.3", - "erc20:eth:BUSD": "1.11.3", + "erc20:eth:AXS": "1.10.3", + "erc20:eth:BUSD": "1.9.0", "erc20:eth:CHZ": "1.11.3", "erc20:eth:CRO": "1.11.3", - "erc20:eth:DAI": "1.11.3", + "erc20:eth:DAI": "1.11.2", "erc20:eth:FRAX": "1.11.3", - "erc20:eth:LEO": "1.11.3", + "erc20:eth:LEO": "1.8.4", "erc20:eth:LINK": "1.11.3", - "erc20:eth:MANA": "1.11.3", - "erc20:eth:MATIC": "1.11.3", - "erc20:eth:OKB": "1.11.3", - "erc20:eth:QNT": "1.11.3", + "erc20:eth:MANA": "1.6.2", + "erc20:eth:MATIC": "1.9.0", + "erc20:eth:OKB": "1.9.5", + "erc20:eth:QNT": "1.6.3", "erc20:eth:SAND": "1.11.3", - "erc20:eth:SHIB": "1.11.3", + "erc20:eth:SHIB": "1.10.4", "erc20:eth:STETH": "1.11.3", - "erc20:eth:UNI": "1.11.3", - "erc20:eth:USDC": "1.11.3", - "erc20:eth:USDT": "1.11.3", - "erc20:eth:WBTC": "1.11.3", + "erc20:eth:UNI": "1.9.5", + "erc20:eth:USDC": "1.7.1", + "erc20:eth:USDT": "1.8.0", + "erc20:eth:WBTC": "1.8.0", "erc20:eth:XCN": "1.11.3", "erc20:matic:WAVAX": "1.11.3", - "eth:BNB:56": "1.11.3", - "eth:ETC:61": "1.11.3", - "eth:ETH:1": "1.11.3", - "eth:MATIC:137": "1.11.3", - "eth:tETH:3": "1.6.2", - "eth:tETH:4": "1.11.3", - "eth:tETH:5": "1.11.3", + "eth:BNB:56": "1.9.4", + "eth:ETC:61": "1.6.2", + "eth:ETH:1": "1.6.2", + "eth:POL:137": "1.9.4", + "eth:tSEP:11155111": "1.11.3", + "eth:tHOL:17000": "1.11.3", "misc:MAID": "1.7.2", "misc:OMNI": "1.7.2", "misc:USDT": "1.7.2", @@ -103,6 +102,7 @@ "bitcoin:tPART": "incompatible fork", "misc:ADA": "not implemented", "misc:BNB": "not implemented", + "misc:DSOL": "not implemented for T1", "misc:EOS": "not implemented", "misc:LSK": "Incompatible mainnet hard-fork", "misc:SOL": "not implemented for T1", @@ -187,12 +187,12 @@ "eth:BNB:56": "2.6.1", "eth:ETC:61": "2.6.1", "eth:ETH:1": "2.6.1", - "eth:MATIC:137": "2.6.1", - "eth:tETH:3": "2.6.1", - "eth:tETH:4": "2.6.1", - "eth:tETH:5": "2.6.1", + "eth:POL:137": "2.6.1", + "eth:tSEP:11155111": "2.6.4", + "eth:tHOL:17000": "2.6.4", "misc:ADA": "2.6.1", "misc:BNB": "2.6.1", + "misc:DSOL": "2.6.4", "misc:MAID": "2.6.1", "misc:OMNI": "2.6.1", "misc:SOL": "2.6.4", @@ -202,12 +202,7 @@ "misc:XRP": "2.6.1", "misc:XTZ": "2.6.1", "misc:tADA": "2.6.1", - "misc:tXRP": "2.6.1", - "nem:BREEZE": "2.6.1", - "nem:DIM": "2.6.1", - "nem:DIMTOK": "2.6.1", - "nem:PAC:CHS": "2.6.1", - "nem:PAC:HRT": "2.6.1" + "misc:tXRP": "2.6.1" }, "unsupported": { "bitcoin:BTG": "not for T2B1 (#2793)", @@ -224,7 +219,12 @@ "bitcoin:tPART": "incompatible fork", "misc:EOS": "not for T2B1 (#2793)", "misc:LSK": "Incompatible mainnet hard-fork", - "nem:XEM": "not for T2B1 (#2793)" + "nem:XEM": "not for T2B1 (#2793)", + "nem:BREEZE": "not for T2B1 (#2793)", + "nem:DIM": "not for T2B1 (#2793)", + "nem:DIMTOK": "not for T2B1 (#2793)", + "nem:PAC:CHS": "not for T2B1 (#2793)", + "nem:PAC:HRT": "not for T2B1 (#2793)" } }, "T2T1": { @@ -284,38 +284,38 @@ "bitcoin:tRVN": "2.4.0", "bitcoin:tSMART": "2.0.8", "erc20:bnb:ATOM": "2.5.3", - "erc20:eth:AAVE": "2.5.3", + "erc20:eth:AAVE": "2.4.3", "erc20:eth:APE": "2.5.3", - "erc20:eth:AXS": "2.5.3", - "erc20:eth:BUSD": "2.5.3", + "erc20:eth:AXS": "2.4.2", + "erc20:eth:BUSD": "2.3.0", "erc20:eth:CHZ": "2.5.3", "erc20:eth:CRO": "2.5.3", - "erc20:eth:DAI": "2.5.3", + "erc20:eth:DAI": "2.5.2", "erc20:eth:FRAX": "2.5.3", - "erc20:eth:LEO": "2.5.3", + "erc20:eth:LEO": "2.1.8", "erc20:eth:LINK": "2.5.3", - "erc20:eth:MANA": "2.5.3", - "erc20:eth:MATIC": "2.5.3", - "erc20:eth:OKB": "2.5.3", - "erc20:eth:QNT": "2.5.3", + "erc20:eth:MANA": "2.0.7", + "erc20:eth:MATIC": "2.3.0", + "erc20:eth:OKB": "2.3.7", + "erc20:eth:QNT": "2.0.8", "erc20:eth:SAND": "2.5.3", - "erc20:eth:SHIB": "2.5.3", + "erc20:eth:SHIB": "2.4.3", "erc20:eth:STETH": "2.5.3", - "erc20:eth:UNI": "2.5.3", - "erc20:eth:USDC": "2.5.3", - "erc20:eth:USDT": "2.5.3", - "erc20:eth:WBTC": "2.5.3", + "erc20:eth:UNI": "2.3.7", + "erc20:eth:USDC": "2.0.8", + "erc20:eth:USDT": "2.0.10", + "erc20:eth:WBTC": "2.0.11", "erc20:eth:XCN": "2.5.3", "erc20:matic:WAVAX": "2.5.3", - "eth:BNB:56": "2.5.3", - "eth:ETC:61": "2.5.3", - "eth:ETH:1": "2.5.3", - "eth:MATIC:137": "2.5.3", - "eth:tETH:3": "2.0.7", - "eth:tETH:4": "2.5.3", - "eth:tETH:5": "2.5.3", + "eth:BNB:56": "2.3.5", + "eth:ETC:61": "2.0.7", + "eth:ETH:1": "2.0.7", + "eth:POL:137": "2.3.5", + "eth:tSEP:11155111": "2.5.4", + "eth:tHOL:17000": "2.5.4", "misc:ADA": "2.0.8", "misc:BNB": "2.1.5", + "misc:DSOL": "2.6.4", "misc:EOS": "2.1.1", "misc:MAID": "2.0.10", "misc:OMNI": "2.0.10", @@ -341,87 +341,232 @@ "misc:LSK": "Incompatible mainnet hard-fork" } }, - "connect": { + "T3B1": { "supported": { - "bitcoin:ACM": true, - "bitcoin:AXE": true, - "bitcoin:BCH": true, - "bitcoin:BTC": true, - "bitcoin:BTCP": true, - "bitcoin:BTG": true, - "bitcoin:BTX": true, - "bitcoin:DASH": true, - "bitcoin:DCR": true, - "bitcoin:DGB": true, - "bitcoin:DOGE": true, - "bitcoin:FIRO": true, - "bitcoin:FJC": true, - "bitcoin:FLO": true, - "bitcoin:FTC": true, - "bitcoin:KMD": true, - "bitcoin:KOTO": true, - "bitcoin:LTC": true, - "bitcoin:MONA": true, - "bitcoin:NMC": true, - "bitcoin:PPC": true, - "bitcoin:REGTEST": true, - "bitcoin:RITO": true, - "bitcoin:RVN": true, - "bitcoin:SYS": true, - "bitcoin:TAZ": true, - "bitcoin:TBCH": true, - "bitcoin:TBTG": true, - "bitcoin:TDCR": true, - "bitcoin:TEST": true, - "bitcoin:UNO": true, - "bitcoin:VIA": true, - "bitcoin:VTC": true, - "bitcoin:XPM": true, - "bitcoin:XRC": true, - "bitcoin:XSN": true, - "bitcoin:XVG": true, - "bitcoin:ZCR": true, - "bitcoin:ZEC": true, - "bitcoin:tDASH": true, - "bitcoin:tFIRO": true, - "bitcoin:tLTC": true, - "bitcoin:tPPC": true, - "eth:tETH:3": true, - "misc:ADA": true, - "misc:BNB": true, - "misc:EOS": true, - "misc:XLM": true, - "misc:XRP": true, - "misc:XTZ": true, - "misc:tADA": true, - "misc:tXRP": true, - "nem:BREEZE": true, - "nem:DIM": true, - "nem:DIMTOK": true, - "nem:PAC:CHS": true, - "nem:PAC:HRT": true, - "nem:XEM": true + "bitcoin:ACM": "2.8.1", + "bitcoin:AXE": "2.8.1", + "bitcoin:BCH": "2.8.1", + "bitcoin:BTC": "2.8.1", + "bitcoin:BTCP": "2.8.1", + "bitcoin:BTX": "2.8.1", + "bitcoin:CPU": "2.8.1", + "bitcoin:CRW": "2.8.1", + "bitcoin:DOGE": "2.8.1", + "bitcoin:ELEMENTS": "2.8.1", + "bitcoin:FIRO": "2.8.1", + "bitcoin:FJC": "2.8.1", + "bitcoin:FLO": "2.8.1", + "bitcoin:FTC": "2.8.1", + "bitcoin:GRS": "2.8.1", + "bitcoin:KMD": "2.8.1", + "bitcoin:KOTO": "2.8.1", + "bitcoin:LTC": "2.8.1", + "bitcoin:MONA": "2.8.1", + "bitcoin:PPC": "2.8.1", + "bitcoin:QTUM": "2.8.1", + "bitcoin:REGTEST": "2.8.1", + "bitcoin:RITO": "2.8.1", + "bitcoin:RVN": "2.8.1", + "bitcoin:SMART": "2.8.1", + "bitcoin:SYS": "2.8.1", + "bitcoin:TAZ": "2.8.1", + "bitcoin:TBCH": "2.8.1", + "bitcoin:TEST": "2.8.1", + "bitcoin:UNO": "2.8.1", + "bitcoin:VIA": "2.8.1", + "bitcoin:VIPS": "2.8.1", + "bitcoin:XPM": "2.8.1", + "bitcoin:XRC": "2.8.1", + "bitcoin:XSN": "2.8.1", + "bitcoin:XVG": "2.8.1", + "bitcoin:ZCR": "2.8.1", + "bitcoin:ZEC": "2.8.1", + "bitcoin:tFIRO": "2.8.1", + "bitcoin:tGRS": "2.8.1", + "bitcoin:tLTC": "2.8.1", + "bitcoin:tPPC": "2.8.1", + "bitcoin:tQTUM": "2.8.1", + "bitcoin:tRVN": "2.8.1", + "bitcoin:tSMART": "2.8.1", + "erc20:bnb:ATOM": "2.8.1", + "erc20:eth:AAVE": "2.8.1", + "erc20:eth:APE": "2.8.1", + "erc20:eth:AXS": "2.8.1", + "erc20:eth:BUSD": "2.8.1", + "erc20:eth:CHZ": "2.8.1", + "erc20:eth:CRO": "2.8.1", + "erc20:eth:DAI": "2.8.1", + "erc20:eth:FRAX": "2.8.1", + "erc20:eth:LEO": "2.8.1", + "erc20:eth:LINK": "2.8.1", + "erc20:eth:MANA": "2.8.1", + "erc20:eth:MATIC": "2.8.1", + "erc20:eth:OKB": "2.8.1", + "erc20:eth:QNT": "2.8.1", + "erc20:eth:SAND": "2.8.1", + "erc20:eth:SHIB": "2.8.1", + "erc20:eth:STETH": "2.8.1", + "erc20:eth:UNI": "2.8.1", + "erc20:eth:USDC": "2.8.1", + "erc20:eth:USDT": "2.8.1", + "erc20:eth:WBTC": "2.8.1", + "erc20:eth:XCN": "2.8.1", + "erc20:matic:WAVAX": "2.8.1", + "eth:BNB:56": "2.8.1", + "eth:ETC:61": "2.8.1", + "eth:ETH:1": "2.8.1", + "eth:POL:137": "2.8.1", + "eth:tSEP:11155111": "2.8.1", + "eth:tHOL:17000": "2.8.1", + "misc:ADA": "2.8.1", + "misc:BNB": "2.8.1", + "misc:DSOL": "2.8.1", + "misc:MAID": "2.8.1", + "misc:OMNI": "2.8.1", + "misc:SOL": "2.8.1", + "misc:USDT": "2.8.1", + "misc:XLM": "2.8.1", + "misc:XMR": "2.8.1", + "misc:XRP": "2.8.1", + "misc:XTZ": "2.8.1", + "misc:tADA": "2.8.1", + "misc:tXRP": "2.8.1" }, - "unsupported": {} + "unsupported": { + "bitcoin:BTG": "not for T3B1 (#2793)", + "bitcoin:DASH": "not for T3B1 (#2793)", + "bitcoin:DCR": "not for T3B1 (#2793)", + "bitcoin:DGB": "not for T3B1 (#2793)", + "bitcoin:NMC": "not for T3B1 (#2793)", + "bitcoin:PART": "incompatible fork", + "bitcoin:TBTG": "not for T3B1 (#2793)", + "bitcoin:TDCR": "not for T3B1 (#2793)", + "bitcoin:TRC": "address_type collides with Bitcoin", + "bitcoin:VTC": "not for T3B1 (#2793)", + "bitcoin:tDASH": "not for T3B1 (#2793)", + "bitcoin:tPART": "incompatible fork", + "misc:EOS": "not for T3B1 (#2793)", + "misc:LSK": "Incompatible mainnet hard-fork", + "nem:XEM": "not for T3B1 (#2793)", + "nem:BREEZE": "not for T3B1 (#2793)", + "nem:DIM": "not for T3B1 (#2793)", + "nem:DIMTOK": "not for T3B1 (#2793)", + "nem:PAC:CHS": "not for T3B1 (#2793)", + "nem:PAC:HRT": "not for T3B1 (#2793)" + } }, - "suite": { + "T3T1": { "supported": { - "bitcoin:BCH": true, - "bitcoin:BTC": true, - "bitcoin:BTG": true, - "bitcoin:DASH": true, - "bitcoin:DGB": true, - "bitcoin:DOGE": true, - "bitcoin:LTC": true, - "bitcoin:NMC": true, - "bitcoin:REGTEST": true, - "bitcoin:TEST": true, - "bitcoin:VTC": true, - "bitcoin:ZEC": true, - "eth:tETH:3": true, - "misc:XRP": true, - "misc:tXRP": true + "bitcoin:ACM": "2.6.1", + "bitcoin:AXE": "2.6.1", + "bitcoin:BCH": "2.6.1", + "bitcoin:BTC": "2.6.1", + "bitcoin:BTCP": "2.6.1", + "bitcoin:BTX": "2.6.1", + "bitcoin:CPU": "2.6.1", + "bitcoin:CRW": "2.6.1", + "bitcoin:DOGE": "2.6.1", + "bitcoin:ELEMENTS": "2.6.1", + "bitcoin:FIRO": "2.6.1", + "bitcoin:FJC": "2.6.1", + "bitcoin:FLO": "2.6.1", + "bitcoin:FTC": "2.6.1", + "bitcoin:GRS": "2.6.1", + "bitcoin:KMD": "2.6.1", + "bitcoin:KOTO": "2.6.1", + "bitcoin:LTC": "2.6.1", + "bitcoin:MONA": "2.6.1", + "bitcoin:PPC": "2.6.1", + "bitcoin:QTUM": "2.6.1", + "bitcoin:REGTEST": "2.6.1", + "bitcoin:RITO": "2.6.1", + "bitcoin:RVN": "2.6.1", + "bitcoin:SMART": "2.6.1", + "bitcoin:SYS": "2.6.1", + "bitcoin:TAZ": "2.6.1", + "bitcoin:TBCH": "2.6.1", + "bitcoin:TEST": "2.6.1", + "bitcoin:UNO": "2.6.1", + "bitcoin:VIA": "2.6.1", + "bitcoin:VIPS": "2.6.1", + "bitcoin:XPM": "2.6.1", + "bitcoin:XRC": "2.6.1", + "bitcoin:XSN": "2.6.1", + "bitcoin:XVG": "2.6.1", + "bitcoin:ZCR": "2.6.1", + "bitcoin:ZEC": "2.6.1", + "bitcoin:tFIRO": "2.6.1", + "bitcoin:tGRS": "2.6.1", + "bitcoin:tLTC": "2.6.1", + "bitcoin:tPPC": "2.6.1", + "bitcoin:tQTUM": "2.6.1", + "bitcoin:tRVN": "2.6.1", + "bitcoin:tSMART": "2.6.1", + "erc20:bnb:ATOM": "2.6.1", + "erc20:eth:AAVE": "2.6.1", + "erc20:eth:APE": "2.6.1", + "erc20:eth:AXS": "2.6.1", + "erc20:eth:BUSD": "2.6.1", + "erc20:eth:CHZ": "2.6.1", + "erc20:eth:CRO": "2.6.1", + "erc20:eth:DAI": "2.6.1", + "erc20:eth:FRAX": "2.6.1", + "erc20:eth:LEO": "2.6.1", + "erc20:eth:LINK": "2.6.1", + "erc20:eth:MANA": "2.6.1", + "erc20:eth:MATIC": "2.6.1", + "erc20:eth:OKB": "2.6.1", + "erc20:eth:QNT": "2.6.1", + "erc20:eth:SAND": "2.6.1", + "erc20:eth:SHIB": "2.6.1", + "erc20:eth:STETH": "2.6.1", + "erc20:eth:UNI": "2.6.1", + "erc20:eth:USDC": "2.6.1", + "erc20:eth:USDT": "2.6.1", + "erc20:eth:WBTC": "2.6.1", + "erc20:eth:XCN": "2.6.1", + "erc20:matic:WAVAX": "2.6.1", + "eth:BNB:56": "2.6.1", + "eth:ETC:61": "2.6.1", + "eth:ETH:1": "2.6.1", + "eth:POL:137": "2.6.1", + "eth:tSEP:11155111": "2.6.1", + "eth:tHOL:17000": "2.6.1", + "misc:ADA": "2.6.1", + "misc:BNB": "2.6.1", + "misc:DSOL": "2.6.4", + "misc:MAID": "2.6.1", + "misc:OMNI": "2.6.1", + "misc:SOL": "2.6.4", + "misc:USDT": "2.6.1", + "misc:XLM": "2.6.1", + "misc:XMR": "2.6.1", + "misc:XRP": "2.6.1", + "misc:XTZ": "2.6.1", + "misc:tADA": "2.6.1", + "misc:tXRP": "2.6.1" }, - "unsupported": {} + "unsupported": { + "bitcoin:BTG": "not for T3T1 (#2793)", + "bitcoin:DASH": "not for T3T1 (#2793)", + "bitcoin:DCR": "not for T3T1 (#2793)", + "bitcoin:DGB": "not for T3T1 (#2793)", + "bitcoin:NMC": "not for T3T1 (#2793)", + "bitcoin:PART": "incompatible fork", + "bitcoin:TBTG": "not for T3T1 (#2793)", + "bitcoin:TDCR": "not for T3T1 (#2793)", + "bitcoin:TRC": "address_type collides with Bitcoin", + "bitcoin:VTC": "not for T3T1 (#2793)", + "bitcoin:tDASH": "not for T3T1 (#2793)", + "bitcoin:tPART": "incompatible fork", + "misc:EOS": "not for T3T1 (#2793)", + "misc:LSK": "Incompatible mainnet hard-fork", + "nem:XEM": "not for T3T1 (#2793)", + "nem:BREEZE": "not for T3T1 (#2793)", + "nem:DIM": "not for T3T1 (#2793)", + "nem:DIMTOK": "not for T3T1 (#2793)", + "nem:PAC:CHS": "not for T3T1 (#2793)", + "nem:PAC:HRT": "not for T3T1 (#2793)" + } } } diff --git a/common/protob/messages-bitcoin.proto b/common/protob/messages-bitcoin.proto index 2b3ff3035d..c6c1b7df9d 100644 --- a/common/protob/messages-bitcoin.proto +++ b/common/protob/messages-bitcoin.proto @@ -212,8 +212,8 @@ message SignTx { required uint32 fee_rate = 1; // coordination fee rate in units of 10^-6 percent required uint64 no_fee_threshold = 2; // PlebsDontPayThreshold in Wasabi, the input amount above which the fee rate applies required uint64 min_registrable_amount = 3; // minimum registrable output amount - required bytes mask_public_key = 4; // ephemeral secp256k1 public key used for masking coinjoin_flags, 33 bytes in compressed form - required bytes signature = 5; // the trusted party's signature of the CoinJoin request digest + optional bytes mask_public_key = 4; // ephemeral secp256k1 public key used for masking coinjoin_flags, 33 bytes in compressed form + optional bytes signature = 5; // the trusted party's signature of the CoinJoin request digest } } diff --git a/common/protob/messages-cardano.proto b/common/protob/messages-cardano.proto index b1331beee9..0f259027a1 100644 --- a/common/protob/messages-cardano.proto +++ b/common/protob/messages-cardano.proto @@ -56,6 +56,16 @@ enum CardanoCertificateType { STAKE_DEREGISTRATION = 1; STAKE_DELEGATION = 2; STAKE_POOL_REGISTRATION = 3; + STAKE_REGISTRATION_CONWAY = 7; + STAKE_DEREGISTRATION_CONWAY = 8; + VOTE_DELEGATION = 9; +} + +enum CardanoDRepType { + KEY_HASH = 0; + SCRIPT_HASH = 1; + ABSTAIN = 2; + NO_CONFIDENCE = 3; } enum CardanoPoolRelayType { @@ -225,6 +235,7 @@ message CardanoSignTxInit { optional uint64 total_collateral = 20; optional uint32 reference_inputs_count = 21 [default=0]; optional bool chunkify = 22; // display the address in chunks of 4 characters + optional bool tag_cbor_sets = 23 [default=false]; // use tag 258 for sets in cbor } /** @@ -335,6 +346,16 @@ message CardanoPoolParametersType { required uint32 relays_count = 12; // number of pool relays } +/** + * DRep delegation parameters + * @embed +*/ +message CardanoDRep { + required CardanoDRepType type = 1; // drep type + optional bytes key_hash = 2; // drep key hash + optional bytes script_hash = 3; // drep script hash +} + /** * Request: Transaction certificate data * @next CardanoTxItemAck @@ -346,6 +367,8 @@ message CardanoTxCertificate { optional CardanoPoolParametersType pool_parameters = 4; // used for stake pool registration certificate optional bytes script_hash = 5; // stake credential script hash optional bytes key_hash = 6; // stake credential key hash + optional uint64 deposit = 7; // used for stake key registration certificate + optional CardanoDRep drep = 8; // used for vote delegation certificate } /** diff --git a/common/protob/messages-common.proto b/common/protob/messages-common.proto index e7a0ac7153..500ddf7389 100644 --- a/common/protob/messages-common.proto +++ b/common/protob/messages-common.proto @@ -49,8 +49,14 @@ message Failure { * @next ButtonAck */ message ButtonRequest { - optional ButtonRequestType code = 1; // enum identifier of the screen + optional ButtonRequestType code = 1; // enum identifier of the screen (deprecated) optional uint32 pages = 2; // if the screen is paginated, number of pages + + // this existed briefly: https://github.com/trezor/trezor-firmware/commit/1012ee8497b241e8ca559e386d936fa549bc0357 + reserved 3; + + optional string name = 4; // name of the screen + /** * Type of button request */ diff --git a/common/protob/messages-crypto.proto b/common/protob/messages-crypto.proto index f33f9609ea..de39735d2a 100644 --- a/common/protob/messages-crypto.proto +++ b/common/protob/messages-crypto.proto @@ -89,44 +89,3 @@ message ECDHSessionKey { required bytes session_key = 1; // ECDH session key optional bytes public_key = 2; // identity public key } - -/** - * Request: Ask device to commit to CoSi signing - * @start - * @next CosiCommitment - * @next Failure - */ -message CosiCommit { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - optional bytes data = 2 [deprecated=true]; // Data to be signed. Deprecated in 1.10.2, the field is not needed, since CoSi commitments are no longer deterministic. -} - -/** - * Response: Contains a CoSi commitment - * @end - */ -message CosiCommitment { - required bytes commitment = 1; // Commitment - required bytes pubkey = 2; // Public key -} - -/** - * Request: Ask device to sign using CoSi - * @start - * @next CosiSignature - * @next Failure - */ -message CosiSign { - repeated uint32 address_n = 1; // BIP-32 path to derive the key from master node - required bytes data = 2; // Data to be signed - required bytes global_commitment = 3; // Aggregated commitment - required bytes global_pubkey = 4; // Aggregated public key -} - -/** - * Response: Contains a CoSi signature - * @end - */ -message CosiSignature { - required bytes signature = 1; // Signature -} diff --git a/common/protob/messages-debug.proto b/common/protob/messages-debug.proto index d508311f91..bdac48b0c2 100644 --- a/common/protob/messages-debug.proto +++ b/common/protob/messages-debug.proto @@ -204,3 +204,12 @@ message DebugLinkWatchLayout { */ message DebugLinkResetDebugEvents { } + + +/** + * Request: Set Optiga's security even counter to maximum + * @start + * @next Success + */ +message DebugLinkOptigaSetSecMax { +} diff --git a/common/protob/messages-management.proto b/common/protob/messages-management.proto index 4c5c8f6003..d743e91329 100644 --- a/common/protob/messages-management.proto +++ b/common/protob/messages-management.proto @@ -13,9 +13,12 @@ import "messages.proto"; * Type of the mnemonic backup given/received by the device during reset/recovery. */ enum BackupType { - Bip39 = 0; // also called "Single Backup", see BIP-0039 - Slip39_Basic = 1; // also called "Shamir Backup", see SLIP-0039 - Slip39_Advanced = 2; // also called "Super Shamir" or "Shamir with Groups", see SLIP-0039#two-level-scheme + Bip39 = 0; // also called "Single Backup", see BIP-0039 + Slip39_Basic = 1; // also called "Shamir Backup", see SLIP-0039 + Slip39_Advanced = 2; // also called "Super Shamir" or "Shamir with Groups", see SLIP-0039#two-level-scheme + Slip39_Single_Extendable = 3; // extendable single-share Shamir backup + Slip39_Basic_Extendable = 4; // extendable multi-share Shamir backup + Slip39_Advanced_Extendable = 5; // extendable multi-share Shamir backup with groups } /** @@ -78,7 +81,7 @@ message Features { optional bool unlocked = 16; // is the device unlocked? called "pin_cached" previously optional bool _passphrase_cached = 17 [deprecated=true]; // is passphrase already cached in session? optional bool firmware_present = 18; // is valid firmware loaded? - optional bool needs_backup = 19; // does storage need backup? (equals to Storage.needs_backup) + optional BackupAvailability backup_availability = 19; // does storage need backup? is repeated backup unlocked? optional uint32 flags = 20; // device flags (equals to Storage.flags) optional string model = 21; // device hardware model optional uint32 fw_major = 22; // reported firmware version if in bootloader mode @@ -88,8 +91,48 @@ message Features { // optional bytes fw_vendor_keys = 26; // obsoleted, use fw_vendor optional bool unfinished_backup = 27; // report unfinished backup (equals to Storage.unfinished_backup) optional bool no_backup = 28; // report no backup (equals to Storage.no_backup) - optional bool recovery_mode = 29; // is recovery mode in progress + optional RecoveryStatus recovery_status = 29; // whether or not we are in recovery mode and of what kind repeated Capability capabilities = 30; // list of supported capabilities + optional BackupType backup_type = 31; // type of device backup (BIP-39 / SLIP-39 basic / SLIP-39 advanced) + optional bool sd_card_present = 32; // is SD card present + optional bool sd_protection = 33; // is SD Protect enabled + optional bool wipe_code_protection = 34; // is wipe code protection enabled + optional bytes session_id = 35; + optional bool passphrase_always_on_device = 36; // device enforces passphrase entry on Trezor + optional SafetyCheckLevel safety_checks = 37; // safety check level, set to Prompt to limit path namespace enforcement + optional uint32 auto_lock_delay_ms = 38; // number of milliseconds after which the device locks itself + optional uint32 display_rotation = 39; // in degrees from North + optional bool experimental_features = 40; // are experimental message types enabled? + optional bool busy = 41; // is the device busy, showing "Do not disconnect"? + optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf, 2 = jpg, 3 = TOIG + optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host? + optional string internal_model = 44; // internal model name + optional uint32 unit_color = 45; // color of the unit/device + optional bool unit_btconly = 46; // unit/device is intended as bitcoin only + optional uint32 homescreen_width = 47; // homescreen width in pixels + optional uint32 homescreen_height = 48; // homescreen height in pixels + optional bool bootloader_locked = 49; // bootloader is locked + optional bool language_version_matches = 50 [default=true]; // translation blob version matches firmware version + optional uint32 unit_packaging = 51; // unit/device packaging version + optional bool haptic_feedback = 52; // haptic feedback is enabled + optional RecoveryType recovery_type = 53; // what type of recovery we are in. NB: this works in conjunction with recovery_status + optional uint32 optiga_sec = 54; // Optiga's security event counter. + + enum BackupAvailability { + /// Device is already backed up, or a previous backup has failed. + NotAvailable = 0; + /// Device is not backed up. Backup is required. + Required = 1; + /// Device is already backed up and can be backed up again. + Available = 2; + } + + enum RecoveryStatus { + Nothing = 0; // we are not in recovery mode + Recovery = 1; // we are in "Normal" or "DryRun" recovery + Backup = 2; // we are in repeated backup mode + } + enum Capability { option (has_bitcoin_only_values) = true; @@ -112,28 +155,9 @@ message Features { Capability_PassphraseEntry = 17 [(bitcoin_only) = true]; // the device is capable of passphrase entry directly on the device Capability_Solana = 18; Capability_Translations = 19 [(bitcoin_only) = true]; + Capability_Brightness = 20 [(bitcoin_only) = true]; + Capability_Haptic = 21 [(bitcoin_only) = true]; } - optional BackupType backup_type = 31; // type of device backup (BIP-39 / SLIP-39 basic / SLIP-39 advanced) - optional bool sd_card_present = 32; // is SD card present - optional bool sd_protection = 33; // is SD Protect enabled - optional bool wipe_code_protection = 34; // is wipe code protection enabled - optional bytes session_id = 35; - optional bool passphrase_always_on_device = 36; // device enforces passphrase entry on Trezor - optional SafetyCheckLevel safety_checks = 37; // safety check level, set to Prompt to limit path namespace enforcement - optional uint32 auto_lock_delay_ms = 38; // number of milliseconds after which the device locks itself - optional uint32 display_rotation = 39; // in degrees from North - optional bool experimental_features = 40; // are experimental message types enabled? - optional bool busy = 41; // is the device busy, showing "Do not disconnect"? - optional HomescreenFormat homescreen_format = 42; // format of the homescreen, 1 = TOIf, 2 = jpg, 3 = TOIG - optional bool hide_passphrase_from_host = 43; // should we hide the passphrase when it comes from host? - optional string internal_model = 44; // internal model name - optional uint32 unit_color = 45; // color of the unit/device - optional bool unit_btconly = 46; // unit/device is intended as bitcoin only - optional uint32 homescreen_width = 47; // homescreen width in pixels - optional uint32 homescreen_height = 48; // homescreen height in pixels - optional bool bootloader_locked = 49; // bootloader is locked - optional bool language_version_matches = 50 [default=true]; // translation blob version matches firmware version - optional uint32 unit_packaging = 51; // unit/device packaging version } /** @@ -181,6 +205,7 @@ message ApplySettings { optional SafetyCheckLevel safety_checks = 9; // Safety check level, set to Prompt to limit path namespace enforcement optional bool experimental_features = 10; // enable experimental message types optional bool hide_passphrase_from_host = 11; // do not show passphrase coming from host + optional bool haptic_feedback = 13; // enable haptic feedback } /** @@ -379,7 +404,7 @@ message LoadDevice { * @next Failure */ message ResetDevice { - optional bool display_random = 1; // display entropy generated by the device before asking for additional entropy + reserved 1; // unused display_random optional uint32 strength = 2 [default=256]; // strength of seed in bits optional bool passphrase_protection = 3; // enable master node encryption using passphrase optional bool pin_protection = 4; // enable PIN protection @@ -427,31 +452,37 @@ message EntropyAck { * @next WordRequest */ message RecoveryDevice { - optional uint32 word_count = 1; // number of words in BIP-39 mnemonic - optional bool passphrase_protection = 2; // enable master node encryption using passphrase - optional bool pin_protection = 3; // enable PIN protection - optional string language = 4 [deprecated=true]; // deprecated (use ChangeLanguage) - optional string label = 5; // device label - optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process - // 7 reserved for unused recovery method - optional RecoveryDeviceType type = 8; // supported recovery type - optional uint32 u2f_counter = 9; // U2F counter - optional bool dry_run = 10; // perform dry-run recovery workflow (for safe mnemonic validation) + optional uint32 word_count = 1; // number of words in BIP-39 mnemonic (T1 only) + optional bool passphrase_protection = 2; // enable master node encryption using passphrase + optional bool pin_protection = 3; // enable PIN protection + optional string language = 4 [deprecated=true]; // deprecated (use ChangeLanguage) + optional string label = 5; // device label + optional bool enforce_wordlist = 6; // enforce BIP-39 wordlist during the process (T1 only) + reserved 7; // unused recovery method + optional RecoveryDeviceInputMethod input_method = 8; // supported recovery input method (T1 only) + optional uint32 u2f_counter = 9; // U2F counter + optional RecoveryType type = 10 [default=NormalRecovery]; // the type of recovery to perform /** * Type of recovery procedure. These should be used as bitmask, e.g., - * `RecoveryDeviceType_ScrambledWords | RecoveryDeviceType_Matrix` + * `RecoveryDeviceInputMethod_ScrambledWords | RecoveryDeviceInputMethod_Matrix` * listing every method supported by the host computer. * * Note that ScrambledWords must be supported by every implementation * for backward compatibility; there is no way to not support it. */ - enum RecoveryDeviceType { + enum RecoveryDeviceInputMethod { // use powers of two when extending this field - RecoveryDeviceType_ScrambledWords = 0; // words in scrambled order - RecoveryDeviceType_Matrix = 1; // matrix recovery type + ScrambledWords = 0; // words in scrambled order + Matrix = 1; // matrix recovery type } } +enum RecoveryType { + NormalRecovery = 0; // recovery from seedphrase on an uninitialized device + DryRun = 1; // mnemonic validation + UnlockRepeatedBackup = 2; // unlock SLIP-39 repeated backup +} + /** * Response: Device is waiting for user to enter word of the mnemonic * Its position is shown only on device's internal display. @@ -609,3 +640,12 @@ message ShowDeviceTutorial { */ message UnlockBootloader { } + +/** + * Request: Set device brightness + * @start + * @next Success + */ +message SetBrightness { + optional uint32 value = 1; // if not specified, let the user choose +} diff --git a/common/protob/messages.proto b/common/protob/messages.proto index f0a5d0cf50..8f00d40f6f 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -127,6 +127,7 @@ enum MessageType { MessageType_ChangeLanguage = 990 [(bitcoin_only) = true, (wire_in) = true]; MessageType_TranslationDataRequest = 991 [(bitcoin_only) = true, (wire_out) = true]; MessageType_TranslationDataAck = 992 [(bitcoin_only) = true, (wire_in) = true]; + MessageType_SetBrightness = 993 [(bitcoin_only) = true, (wire_in) = true]; MessageType_SetU2FCounter = 63 [(wire_in) = true]; MessageType_GetNextU2FCounter = 80 [(wire_in) = true]; @@ -168,10 +169,8 @@ enum MessageType { MessageType_SignedIdentity = 54 [(bitcoin_only) = true, (wire_out) = true]; MessageType_GetECDHSessionKey = 61 [(bitcoin_only) = true, (wire_in) = true]; MessageType_ECDHSessionKey = 62 [(bitcoin_only) = true, (wire_out) = true]; - MessageType_CosiCommit = 71 [(bitcoin_only) = true, (wire_in) = true]; - MessageType_CosiCommitment = 72 [(bitcoin_only) = true, (wire_out) = true]; - MessageType_CosiSign = 73 [(bitcoin_only) = true, (wire_in) = true]; - MessageType_CosiSignature = 74 [(bitcoin_only) = true, (wire_out) = true]; + // dropped: CosiCommit, CosiCommitment, CosiSign, CosiSignature + reserved 71 to 74; // Debug MessageType_DebugLinkDecision = 100 [(bitcoin_only) = true, (wire_debug_in) = true, (wire_tiny) = true, (wire_no_fsm) = true]; @@ -189,6 +188,7 @@ enum MessageType { MessageType_DebugLinkEraseSdCard = 9005 [(bitcoin_only) = true, (wire_debug_in) = true]; MessageType_DebugLinkWatchLayout = 9006 [(bitcoin_only) = true, (wire_debug_in) = true]; MessageType_DebugLinkResetDebugEvents = 9007 [(bitcoin_only) = true, (wire_debug_in) = true]; + MessageType_DebugLinkOptigaSetSecMax = 9008 [(bitcoin_only) = true, (wire_debug_in) = true]; // Ethereum MessageType_EthereumGetPublicKey = 450 [(wire_in) = true]; diff --git a/common/tests/fixtures/cardano/sign_tx.failed.json b/common/tests/fixtures/cardano/sign_tx.failed.json index 1a3911c26b..d993594a3c 100644 --- a/common/tests/fixtures/cardano/sign_tx.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.failed.json @@ -37,7 +37,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid input" @@ -76,7 +77,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -115,7 +117,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -154,7 +157,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -193,7 +197,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -232,7 +237,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -271,7 +277,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Fee is out of range" @@ -315,7 +322,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Total transaction amount is out of range!" @@ -354,7 +362,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Output address network mismatch" @@ -393,7 +402,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Output address network mismatch" @@ -432,7 +442,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -471,7 +482,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -510,7 +522,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid network id/protocol magic combination!" @@ -549,7 +562,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid network id/protocol magic combination!" @@ -588,7 +602,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -630,7 +645,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -674,7 +690,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -718,7 +735,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -762,7 +780,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -806,7 +825,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -851,7 +871,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -896,7 +917,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -941,7 +963,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -985,7 +1008,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1029,7 +1053,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1073,7 +1098,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1117,7 +1143,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1161,7 +1188,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1206,7 +1234,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1251,7 +1280,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -1292,7 +1322,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid auxiliary data" @@ -1341,7 +1372,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address parameters" @@ -1392,7 +1424,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid auxiliary data" @@ -1449,7 +1482,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid auxiliary data" @@ -1489,7 +1523,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output datum hash" @@ -1528,7 +1563,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid script data hash" @@ -1573,7 +1609,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1615,7 +1652,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1654,7 +1692,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1698,7 +1737,8 @@ ], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1739,7 +1779,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -1781,7 +1822,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -1826,7 +1868,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid change output path" @@ -1871,7 +1914,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid change output staking path" @@ -1916,7 +1960,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address parameters" @@ -1955,7 +2000,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address" @@ -1999,7 +2045,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate path" @@ -2043,7 +2090,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -2097,7 +2145,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid token bundle in output" @@ -2156,7 +2205,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid token bundle in output" @@ -2209,7 +2259,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid mint token bundle" @@ -2267,7 +2318,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid mint token bundle" @@ -2325,7 +2377,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid token bundle in output" @@ -2393,7 +2446,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid token bundle in output" @@ -2450,7 +2504,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid mint token bundle" @@ -2517,7 +2572,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid mint token bundle" @@ -2560,7 +2616,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2603,7 +2660,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2644,7 +2702,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address parameters" @@ -2734,7 +2793,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2777,7 +2837,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2871,7 +2932,8 @@ "path": "m/1855'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2916,7 +2978,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -2960,7 +3023,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -3004,7 +3068,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -3054,7 +3119,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -3104,7 +3170,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -3153,7 +3220,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -3197,7 +3265,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -3238,7 +3307,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" diff --git a/common/tests/fixtures/cardano/sign_tx.json b/common/tests/fixtures/cardano/sign_tx.json index 52ebc5adab..102bc9fbed 100644 --- a/common/tests/fixtures/cardano/sign_tx.json +++ b/common/tests/fixtures/cardano/sign_tx.json @@ -37,7 +37,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "73e09bdebf98a9e0f17f86a2d11e0f14f4f8dae77cdf26ff1678e821f20c8db6", @@ -89,7 +90,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "81b14b7e62972127eb33c0b1198de6430540ad3a98eec621a3194f2baac43a43", @@ -142,7 +144,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "16fe72bb198be423677577e6326f1f648ec5fc11263b072006382d8125a6edda", @@ -204,7 +207,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "7e16a0b47bdfc37abf4ddd3143f7481af07ffe7abd68f752676f5b0b2890d05b", @@ -275,7 +279,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "5ddbb530b8a89e2b08fc91db03950c876c4a9c1c3fb6e628c4cab638b1c97648", @@ -329,7 +334,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1fc82ce2420c173a0947eaf49af76fcd6f4e400e2bfb5fa152a482ea12dde24b", @@ -383,7 +389,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "abd1b24ac0638251398444ee136110f952738df32a512ce35894f8453d0e8edf", @@ -436,7 +443,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "d1610bb89bece22ed3158738bc1fbb31c6af0685053e2993361e3380f49afad9", @@ -489,7 +497,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1d6fc2044d54d4af5b44e4be4c1ce3670fe4d2e37523a945d087252c27b215f2", @@ -544,7 +553,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "40535fa8f88515f1da008d3cdf544cf9dbf1675c3cb0adb13b74b9293f1b7096", @@ -596,7 +606,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "d3570557b197604109481a80aeb66cd2cfabc57f802ad593bacc12eb658e5d72", @@ -648,7 +659,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1a3a295908afd8b2afc368071272d6964be6ee0af062bb765aea65ca454dc0c9", @@ -662,6 +674,126 @@ ] } }, + { + "description": "transaction with conway stake registration certificate", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 7, + "path": "m/1852'/1815'/0'/2/0", + "deposit": 2000000 + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "e200b2c91f3493a1f3b9cfc8b6c141f70181741025e53941e9d57d22b1470c5c", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "79a357517a08c7256b0fab1e93a92a477386f4c2d72cea7bc68527c0133c32472305f010350665d72e8017bb6c2080b5742680ce7700bbddda561c917f294a07", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "dca542910d0362fc22744e7a24732343db4e013495a7d9b47562886f09af8eb56ecaa105e20a9df3e4248fdab61dd91b6fb2a3bfc15d0d9a0442671c07e1ba02", + "chain_code": null + } + ] + } + }, + { + "description": "transaction with conway stake registration certificate and 258-tagged sets", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 7, + "path": "m/1852'/1815'/0'/2/0", + "deposit": 2000000 + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": true + }, + "result": { + "tx_hash": "5e27f8fba938603411452a8cb373462fb64305539573b7a9edc9155be5cd6473", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "13c136487d8048ab7bbb081a324aa6b999e0b3237f956503b5446a4c409ec1062091b82e9e5459dee7ab0ba67ed874692d788872c8bbdb5ad4a3975c465fea09", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "f0674db7194d8e04d7df416af8ad9dcf1b1203ca4b78f14c1e394d47418c8f7e95fd41a8f01c43eeeb39df6264359c865a41621fc1e6b540819b25c7c4df5803", + "chain_code": null + } + ] + } + }, { "description": "transaction with stake registration certificate (no outputs)", "parameters": { @@ -695,7 +827,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "03535791d04fc1b4457fada025f1c1f7778b5c2d7fa580bbac8abd53b85d3255", @@ -752,7 +885,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "439764b5f7e08839881536a3191faeaf111e75d9f00f83b102c5c1c6fa9fcaf9", @@ -810,7 +944,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "3aca1784d151dc75bdbb80fae71bda3f4b26af3f5fd71bd5e9e9bbcdd2b64ad1", @@ -830,6 +965,66 @@ ] } }, + { + "description": "transaction with conway stake deregistration certificate", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 8, + "path": "m/1852'/1815'/0'/2/0", + "deposit": 2000000 + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "564ad55097101e1ca85629cffe839f43a19bf33aa1940c99a62eb8f14392eebb", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "a0fa6630498f57249b305824ad4d32157653820e7d651332a58af70a80364df882ee8b0471e76dd7a335eea84a18c52b12c02508779d46b193bc418c22e8a00f", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "5d282fcd2685ee47f3770f84b2badf4046e8e76bfdaa26f74e292ecd16bcf89fb330b99edff13bc9c81e8c6523864f69a3ac7cde29d5a648707724c5cb48730e", + "chain_code": null + } + ] + } + }, { "description": "transaction with stake deregistration and withdrawal", "parameters": { @@ -873,7 +1068,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "22c67f12e6f6aa0f2f09fd27d472b19c7208ccd7c3af4b09604fd5d462c1de2b", @@ -932,7 +1128,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "cc068a25994ef6a90cdab8adfbe302d6f742de9901ba2495dd64a09f2ef951f5", @@ -952,6 +1149,256 @@ ] } }, + { + "description": "transaction delegating vote to DRep by key hash", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 9, + "path": "m/1852'/1815'/0'/2/0", + "drep": { + "type": 0, + "key_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "1669062fd6efc4f11ed8ae9511a9c9f4454fa4f64e2043483f99d7c711236664", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "b900968efd7cfed3666a63f11267bb4fdc08684788883b91cf690e37834263387b164d52c770d1bb91578ca0029a954c9ef787ab0d3b9f3f396dedf744baa80b", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "d4fb5ebae0a061afa784df1ecceda5c06955a59ebc1ca4f7c2457f7ba27eacca756b8be9d84584f1b2ea23ce7b8420c73fc447398cf6caa725cb0d5c9b9f700e", + "chain_code": null + } + ] + } + }, + { + "description": "transaction delegating vote to DRep by script hash", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 9, + "path": "m/1852'/1815'/0'/2/0", + "drep": { + "type": 1, + "script_hash": "29fb5fd4aa8cadd6705acc8263cee0fc62edca5ac38db593fec2f9fd" + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "fccf753e4f96e20c880e5ea933041ed33509ec6c0dc1aee8b25a1fe3d562b7aa", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "bde0242fee0de5b862d2f02847d789ebe10e8f82bf15837370f115c89c1b413f1b0fa5a470210127af92059c4d3ebff297d39e93143667d3823476f12f0f6f07", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "cd8a2fca634c1aa2c88609042de7e4fce232bf233b1271612b5edc7b806e11ff44e6b6b15feb5b6e76b7e16a8d703e7653d860c00981edf6fe3b1e4cbeaba406", + "chain_code": null + } + ] + } + }, + { + "description": "transaction delegating vote to predefined DRep 'Abstain'", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 9, + "path": "m/1852'/1815'/0'/2/0", + "drep": { + "type": 2 + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "01d0f76fadc899087c5352befac56cbfdc2e868ac715fbfe00230bab3f7fa751", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "52c57d9c0e06fc9883285db4eec1a1504e27726dc5afce943d6f54df22188f05c3eeee06d052375eceb55df83c314237b3718f07fccef6198bda8c20d794b102", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "6de4940ff99738aaf3659ffeb8e4f6f01ff88ddb65c24028d75a847ca684d07af000e32eaa4c915c8031f6d928b2bcbe8c6f57e389299d3eafe213bd0ab1190c", + "chain_code": null + } + ] + } + }, + { + "description": "transaction delegating vote to predefined DRep 'No Confidence'", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [ + { + "type": 9, + "path": "m/1852'/1815'/0'/2/0", + "drep": { + "type": 3 + } + } + ], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "3b40265111d8bb3c3c608d95b3a0bf83461ace32d79336579a1939b3aad1c0b7", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": null, + "collateral_inputs": [], + "required_signers": [], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [], + "signing_mode": "ORDINARY_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": false + }, + "result": { + "tx_hash": "567e9bd00787190f1ab51879dcf834002b76007130c526b2e4d1bf9a996f5ad0", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "20e3f9ecc3a1b97cbda08cf610b2e72b45d0e0916af2be2ad472d4c8d2be4b13818497818961c8d27379754f0057b00fa286bce0d59f177f24eeee4e2b24940f", + "chain_code": null + }, + { + "type": 1, + "pub_key": "bc65be1b0b9d7531778a1317c2aa6de936963c3f9ac7d5ee9e9eda25e0c97c5e", + "signature": "898fb2cef0c4b954f22c4218fc9a188a5da340ddb5c6d5bba01c67520bbf537f5743814b6d40dd7f299ece7e39d7efb16a1cb597e8d421649a9483f631371703", + "chain_code": null + } + ] + } + }, { "description": "transaction with auxiliary data hash", "parameters": { @@ -987,7 +1434,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1875f1d59a53f1cb4c43949867d72bcfd857fa3b64feb88f41b78ddaa1a21cbf", @@ -1045,7 +1493,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "839a587109358e0aa81b8fb3d5fa74665fac303425ec544a4db7f6ba4e882dff", @@ -1118,7 +1567,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "15e4e382d913a743776b93d730fee3ca39bfa3ee203801205333bc9aad249612", @@ -1188,7 +1638,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "98357cec961c4c2bfef747bb204a06945ab55077166ec4367b644882136b8b39", @@ -1253,7 +1704,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "a5c5506777fb62aa98e6c45f1c85ab9ddf706a1f199e777c43f2288a6b4fdcab", @@ -1321,7 +1773,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c5b5f451fb5992e97ab50364467348c1899a2c8972d2d79ae5893bbac37eb51f", @@ -1386,7 +1839,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c5b5f451fb5992e97ab50364467348c1899a2c8972d2d79ae5893bbac37eb51f", @@ -1447,7 +1901,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "47cf79f20c6c62edb4162b3b232a57afc1bd0b57c7fd8389555276408a004776", @@ -1511,7 +1966,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "b7269ddc59e4094a6581c653e0d5dc1e553e3a5fb6ffae47d3d094dff1cfe87b", @@ -1588,7 +2044,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "0b929def7bd9f44f5602f809bc0f9be30521f6b93d625525cf33b956993bfb22", @@ -1637,7 +2094,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "b621e22f7cb9aac1a70a3362fde88bdfd31fc100e20f3f3c24a7b853536b4f50", @@ -1695,7 +2153,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "00d393f7fc9a8c17b3efccb44dad9d7e15fdaf2d942a3a455b52b5be016066dd", @@ -1754,7 +2213,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f4b7315ec080d05024d1f7bf6795dd234c6624970d8e272a245702de539feaa2", @@ -1807,7 +2267,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "cabc87a76ad8944e8a97a7cbf9c893a77ed7d1bd963c428c3786d663adb7f0dd", @@ -1959,7 +2420,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f98e1b5edfd376356eb211103bfae679380929bf7fbc40b3355a68e98111d091", @@ -2084,7 +2546,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "042c1d3a6eab693d2ea6b186a88aed038159e7eb581da80464bca7339fb9afe0", @@ -2137,7 +2600,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": true + "include_network_id": true, + "tag_cbor_sets": false }, "result": { "tx_hash": "4fcd4532bb0a9dfff2368e60be80d46819a92a9acfb2c64a7bf5975040789bac", @@ -2185,7 +2649,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8ea2765f1e46d84f02d8b25a5f0cf445aaeaadcab913e17e59388a4f898ca812", @@ -2235,7 +2700,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "b90ad6dd0e1155559bd3e66f2fce91f4c85598d47c90922f01e121ea4f51f96e", @@ -2282,7 +2748,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "06d6587ddd79e000b6922c54069b78bb931b0cba06d97ba4171f3ce6590438d2", @@ -2329,7 +2796,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8606e5b69b5c40bd359d7bad6ed6f77810b8e8acba6cbca298c13f92b11178d4", @@ -2380,7 +2848,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8c328640f974f47cecbcaed56e46c3ba4f2ea6769e6e3528915deb3bb518aa06", @@ -2463,7 +2932,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "b664d33bfcbfc1b54f34c813438ab4dac788ce715a3461f85142c4d19460e949", @@ -2513,7 +2983,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "719d33e1e2811f82046951dccee1a9af82d8fe1d8abc36d581a9eccc421c3204", @@ -2565,7 +3036,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "821e8163c5cf225c09f338f385c81e4326610f830e2abb89f9961e20741e6b70", @@ -2708,7 +3180,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f1bda77315626ce61c784f3e60a74128f29b7d00a0c8baca030464293da2d7c4", @@ -2761,7 +3234,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f2c5b7bd408add0234e2302d1b46cc72e0af8a88e6d12add95d230c51febdb04", @@ -2813,7 +3287,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "62baf68499258a35809faab713420d7d609dd0a1a3bbc5f6e3332917cf5ddece", @@ -2865,7 +3340,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "ac4bdaaf2288a0108654919e7f89811b32274d54da834162e407635db39de4f4", diff --git a/common/tests/fixtures/cardano/sign_tx.multisig.failed.json b/common/tests/fixtures/cardano/sign_tx.multisig.failed.json index caf6fe7bc2..d6bcd7c370 100644 --- a/common/tests/fixtures/cardano/sign_tx.multisig.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.multisig.failed.json @@ -45,7 +45,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -92,7 +93,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -142,7 +144,8 @@ "path": "m/1854'/1815'/2'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -192,7 +195,8 @@ "path": "m/1854'/1815'/2'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -240,7 +244,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -288,7 +293,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -335,7 +341,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -382,7 +389,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -433,7 +441,8 @@ "reference_inputs": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -480,7 +489,8 @@ "reference_inputs": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid withdrawal" @@ -522,7 +532,8 @@ "path": "m/1852'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -566,7 +577,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -608,7 +620,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -701,7 +714,8 @@ "path": "m/1855'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid witness request" @@ -748,7 +762,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -793,7 +808,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -835,7 +851,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -882,7 +899,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" diff --git a/common/tests/fixtures/cardano/sign_tx.multisig.json b/common/tests/fixtures/cardano/sign_tx.multisig.json index 44051c5004..a5e47f6749 100644 --- a/common/tests/fixtures/cardano/sign_tx.multisig.json +++ b/common/tests/fixtures/cardano/sign_tx.multisig.json @@ -94,7 +94,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "042c1d3a6eab693d2ea6b186a88aed038159e7eb581da80464bca7339fb9afe0", @@ -155,7 +156,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "ed9fc2755091fa72b58e9dd06db05cce87c0c6f3962f587d5fc348fe478f0752", @@ -218,7 +220,8 @@ "path": "m/1854'/1815'/0'/2/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "26fb07b23368898665829283985ffe6c4cb2ec13758e83f467b78e5061f9619b", @@ -282,7 +285,8 @@ "path": "m/1854'/1815'/0'/2/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c4e70484c964eca910219047542632ac9a9ac81f11f5d5afd8bb1b0ef4366d69", @@ -351,7 +355,8 @@ "path": "m/1854'/1815'/0'/2/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "e02d252c5cad2a4d8f163069cd7f0822c7876d16af9ad8ac2d461655812b2d1b", @@ -464,7 +469,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": true + "include_network_id": true, + "tag_cbor_sets": false }, "result": { "tx_hash": "c3637e34529fae17dbbb90c58307df0cf3b818f4c034860fff362d1ea864cca4", @@ -527,7 +533,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8ea2765f1e46d84f02d8b25a5f0cf445aaeaadcab913e17e59388a4f898ca812", @@ -577,7 +584,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "ee065ce429d8dbcc2432aa81706877f2eee4fc5031d1e1ae06fe993b9987b1be", @@ -631,7 +639,8 @@ "path": "m/1854'/1815'/0'/0/2" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "dae07f98f82878ecd1a6ad988c55f80870c2fb299705ed181458664906583e51", diff --git a/common/tests/fixtures/cardano/sign_tx.plutus.failed.json b/common/tests/fixtures/cardano/sign_tx.plutus.failed.json index 0f4e8065b2..973a528a5f 100644 --- a/common/tests/fixtures/cardano/sign_tx.plutus.failed.json +++ b/common/tests/fixtures/cardano/sign_tx.plutus.failed.json @@ -43,7 +43,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid collateral input" @@ -89,7 +90,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid address parameters" @@ -138,7 +140,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid required signer" @@ -185,7 +188,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid collateral return" @@ -233,7 +237,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid collateral return" diff --git a/common/tests/fixtures/cardano/sign_tx.plutus.json b/common/tests/fixtures/cardano/sign_tx.plutus.json index 8643c03915..b7fce3e634 100644 --- a/common/tests/fixtures/cardano/sign_tx.plutus.json +++ b/common/tests/fixtures/cardano/sign_tx.plutus.json @@ -42,7 +42,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "598dc85bc03cc682ee7ce8b4db798d836a0840429cae7fc62fe388e727a669a2", @@ -107,7 +108,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "ff4a515636b38ed2b2b37f64501f75f04a25d05349b5b84c07f319b6f86372f4", @@ -139,6 +141,95 @@ ] } }, + { + "description": "Plutus transaction with required signers, reference input and 258-tagged sets", + "parameters": { + "protocol_magic": 764824073, + "network_id": 1, + "fee": 42, + "ttl": 10, + "validity_interval_start": null, + "certificates": [], + "withdrawals": [], + "auxiliary_data": null, + "inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "outputs": [ + { + "address": "addr1q84sh2j72ux0l03fxndjnhctdg7hcppsaejafsa84vh7lwgmcs5wgus8qt4atk45lvt4xfxpjtwfhdmvchdf2m3u3hlsd5tq5r", + "amount": "1" + } + ], + "mint": [], + "script_data_hash": "d593fd793c377ac50a3169bb8378ffc257c944da31aa8f355dfa5a4f6ff89e02", + "collateral_inputs": [ + { + "path": "m/1852'/1815'/0'/0/0", + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "required_signers": [ + { + "key_path": "m/1852'/1815'/0'/0/1" + }, + { + "key_path": "m/1854'/1815'/0'/0/0" + }, + { + "key_path": "m/1855'/1815'/0'" + }, + { + "key_hash": "3a7f09d3df4cf66a7399c2b05bfa234d5a29560c311fc5db4c490711" + } + ], + "collateral_return": null, + "total_collateral": null, + "reference_inputs": [ + { + "prev_hash": "1af8fa0b754ff99253d983894e63a2b09cbb56c833ba18c3384210163f63dcfc", + "prev_index": 0 + } + ], + "signing_mode": "PLUTUS_TRANSACTION", + "additional_witness_requests": [], + "include_network_id": false, + "tag_cbor_sets": true + }, + "result": { + "tx_hash": "9cb88fd25d43f4e8140be00dd9538c59b0e8fe1f3186890421d8820cf33e6be7", + "witnesses": [ + { + "type": 1, + "pub_key": "5d010cf16fdeff40955633d6c565f3844a288a24967cf6b76acbeb271b4f13c1", + "signature": "5f9426495c0fe515a2f933cb43a2d3f4de32b5102e32ce8d71e1d3718fda2b6a91c6845f9d612787096813c8be7aea4bc140c1288ac24f6bedf9d6c105ff7c05", + "chain_code": null + }, + { + "type": 1, + "pub_key": "36a8ef21d5b98fdf23a27325cf643deaac35e912c835e35037f23d1061ae5b16", + "signature": "a2251fc5daa777643db0c12becf35b8d75d14743888beb7f48da0a5c2428bfade90926b4df6f70a9d967b26d6a09208e6278d210fbfc84a5a01ad7d0fd04d90e", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b10be5c0d11ad8292bbe69e220ca0cfbe154610b3041a8e72f9d515c226ab3b1", + "signature": "0a457eca4d1dac83f9f794f07215e625d4af4db361ce303f8744efc609714f4f075805e0ad81c9127bd0d8ad5f22a21b6d166c2d9cab2c8309d90c493956ca07", + "chain_code": null + }, + { + "type": 1, + "pub_key": "b75258e4f61eb7b313d8554c2fe10673cf214ca2d762bfd53ec3b7846e2ee872", + "signature": "f60e26cb4152179ebe9af3beae7c54abe04d4d195efe5cebde1d007084dcce3c664fc43629da524ae33ba9fe40bba8a8f36964845c196fafc182459ad8f7f60e", + "chain_code": null + } + ] + } + }, { "description": "Simple Plutus transaction with additional witness requests", "parameters": { @@ -187,7 +278,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "598dc85bc03cc682ee7ce8b4db798d836a0840429cae7fc62fe388e727a669a2", @@ -255,7 +347,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "3fbf931170d2ed6df95a35572d850b40bab4b350763872cb9110f93e9ce8668b", @@ -316,7 +409,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "08bd557131d89c5008cf79f7bdf9c47d27ad7c00b3a1a19dfecedd7c1f7508d8", @@ -439,7 +533,8 @@ "path": "m/1855'/1815'/0'" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f1ff85026488d1ea60950d9d1819ee00a012560074cd60435f2510e917d86a7f", @@ -512,7 +607,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "0c4a8ec4a0e6718d81a391d09bbc7d48e14f879c94b7e48a35092ef532ebf597", @@ -587,7 +683,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "53d7a7ee887178a08ac70ff2088f8bfbafc7b6bcd5a54e79a686b013455d5e25", @@ -663,7 +760,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c55ef20e0c8da066bab5221a5c010c32d90905753b0257576e34d7e639f65c9d", @@ -744,7 +842,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "b3ccc29173719973363988763826eb853cb314df8dde07fcf82dab9961d47c25", @@ -825,7 +924,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "717e9b63b08fda304bf7625d5df4149200b28b740db9b66082961a1d2f938ccd", @@ -912,7 +1012,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "baabb4e6dced60de330a089590ea38b7bbe505bbf9c785ef88078242f0ea9860", @@ -981,7 +1082,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "bb4d26c40c67d23ca74bb2e4ad28f586567b99907b86c0337fb7d8f4cde90100", @@ -1035,7 +1137,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "5581fb7a99b8e0ebaf552a5d7157cebb37c9624602d78d86337dfbf838fb2e13", @@ -1089,7 +1192,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "e5beff2153154ab3dba4ff5c638f40ae8c1594c67aee3310bd19997f5013e47b", @@ -1143,7 +1247,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "2399f1743e4074d3e18a742898c3e4d5eac66a7284a949ddcd1eac004498720f", @@ -1197,7 +1302,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8c131e38f378d141deb05d4bf2eb2d13bb75d6363dd470a1f524ba027eff566a", @@ -1263,7 +1369,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "6c5ccc9f6ec1b0b25ccb81ae533b9d46e545af4b745f7e287c967f13a152d537", @@ -1331,7 +1438,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c95a6f99f5763d89926b44b8a0f7fa12f14ee3978c120e42c581a3f47638d490", @@ -1383,7 +1491,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "3a2a702ed7a907323a7f6ef7bf5d5ad4685bd1a605a0594e535b93597a33b574", @@ -1449,7 +1558,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "6852e7285d0a187f692bdb2ea93451f96952303c54168d5bd7c428a78d0fac07", @@ -1517,7 +1627,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1bef5859c3e23fad63141b61e03aa45537c5ec10ad7c4780a4ed198c17bee165", @@ -1574,7 +1685,8 @@ ], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "98657251d3014dfd98e1eab94bf0a7f6252968d683df9bc8585bf431b4c72a51", diff --git a/common/tests/fixtures/cardano/sign_tx.show_details.json b/common/tests/fixtures/cardano/sign_tx.show_details.json index 7d89e6cedf..3bf0151414 100644 --- a/common/tests/fixtures/cardano/sign_tx.show_details.json +++ b/common/tests/fixtures/cardano/sign_tx.show_details.json @@ -37,7 +37,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "73e09bdebf98a9e0f17f86a2d11e0f14f4f8dae77cdf26ff1678e821f20c8db6", @@ -94,7 +95,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "22c67f12e6f6aa0f2f09fd27d472b19c7208ccd7c3af4b09604fd5d462c1de2b", @@ -148,7 +150,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8ea2765f1e46d84f02d8b25a5f0cf445aaeaadcab913e17e59388a4f898ca812", @@ -199,7 +202,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "8c328640f974f47cecbcaed56e46c3ba4f2ea6769e6e3528915deb3bb518aa06", @@ -257,7 +261,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "ea6d50d786a7c252451704379a05bb21d3f9ad47d043d90fcc88cad5b78ca3bc", @@ -311,7 +316,8 @@ "path": "m/1854'/1815'/0'/0/2" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "dae07f98f82878ecd1a6ad988c55f80870c2fb299705ed181458664906583e51", @@ -385,7 +391,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "1bef5859c3e23fad63141b61e03aa45537c5ec10ad7c4780a4ed198c17bee165", @@ -442,7 +449,8 @@ ], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "98657251d3014dfd98e1eab94bf0a7f6252968d683df9bc8585bf431b4c72a51", @@ -510,7 +518,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "15e4e382d913a743776b93d730fee3ca39bfa3ee203801205333bc9aad249612", diff --git a/common/tests/fixtures/cardano/sign_tx.slip39.json b/common/tests/fixtures/cardano/sign_tx.slip39.json index 3e0b89907c..a706a91cc1 100644 --- a/common/tests/fixtures/cardano/sign_tx.slip39.json +++ b/common/tests/fixtures/cardano/sign_tx.slip39.json @@ -41,7 +41,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "73e09bdebf98a9e0f17f86a2d11e0f14f4f8dae77cdf26ff1678e821f20c8db6", @@ -93,7 +94,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "4c43ce4c72f145b145ae7add414722735e250d048f61c4585a5becafcbffa6ae", @@ -145,7 +147,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "93a2c3cfb67ef1e4bae167b0f443c3370664bdb9171bc9cd41bad98e5cc049b2", diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json index b13d4f77f0..8548de8c64 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.failed.json @@ -58,7 +58,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -121,7 +122,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -181,7 +183,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -241,7 +244,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -322,7 +326,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -365,7 +370,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -430,7 +436,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -490,7 +497,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Stakepool registration transaction can only contain the pool owner witness request" @@ -549,7 +557,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "ProcessError: Invalid address" @@ -608,7 +617,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "ProcessError: Invalid address" @@ -701,7 +711,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid pool owner staking path" @@ -794,7 +805,8 @@ "reference_inputs": [], "signing_mode": "ORDINARY_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -887,7 +899,8 @@ "reference_inputs": [], "signing_mode": "MULTISIG_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -980,7 +993,8 @@ "reference_inputs": [], "signing_mode": "PLUTUS_TRANSACTION", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid certificate" @@ -1077,7 +1091,8 @@ "path": "m/1854'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Stakepool registration transaction can only contain the pool owner witness request" @@ -1174,7 +1189,8 @@ "path": "m/1855'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Stakepool registration transaction can only contain the pool owner witness request" @@ -1298,7 +1314,8 @@ "path": "m/1855'/1815'/0'/0/0" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1377,7 +1394,7 @@ } ], "outputs": [ - { + { "addressType": 0, "path": "m/1852'/1815'/0'/0/0", "stakingPath": "m/1852'/1815'/0'/2/0", @@ -1393,7 +1410,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -1487,7 +1505,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid output" @@ -1580,7 +1599,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1679,7 +1699,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1775,7 +1796,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1868,7 +1890,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -1966,7 +1989,8 @@ ], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -2063,7 +2087,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Invalid tx signing request" @@ -2160,7 +2185,8 @@ "path": "m/1852'/1815'/0'/2/1" } ], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "error_message": "Stakepool registration transaction can only contain the pool owner witness request" diff --git a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json index 033c577cc7..6c94b85033 100644 --- a/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json +++ b/common/tests/fixtures/cardano/sign_tx_stake_pool_registration.json @@ -91,7 +91,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "e3b9a5657bf62609465a930c8359d774c73944973cfc5a104a0f0ed1e1e8db21", @@ -192,7 +193,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "c0d944db15446cf05e8db014685414c928d4d9a3e96aea229234be56eeae34c5", @@ -294,7 +296,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "f3d62758ff2f520e7256e65be9d8165da60c7979a97202c19d625709412411fd", @@ -362,7 +365,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "504f9214142996e0b7e315103b25d88a4afa3d01dd5be22376921b52b01483c3", @@ -430,7 +434,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "12921b4f8e77f815e0c8ed97c541fbd5ba38a6d3323f4ff1af0cb934b8ac6b39", @@ -533,7 +538,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "880fafab19a36407e9af300c2905e2f6bc8a8debd8b625005f56994d242ba460", @@ -634,7 +640,8 @@ "reference_inputs": [], "signing_mode": "POOL_REGISTRATION_AS_OWNER", "additional_witness_requests": [], - "include_network_id": false + "include_network_id": false, + "tag_cbor_sets": false }, "result": { "tx_hash": "36d7e5b9acc9487b9190c3bbe8fa0ec60a6fd66b3c0af7cfd8a015a18b00d765", diff --git a/common/tests/fixtures/ethereum/sign_tx_eip155.json b/common/tests/fixtures/ethereum/sign_tx_eip155.json index b31965bae1..451d148161 100644 --- a/common/tests/fixtures/ethereum/sign_tx_eip155.json +++ b/common/tests/fixtures/ethereum/sign_tx_eip155.json @@ -23,44 +23,6 @@ "sig_s": "4ae58ccd3bacee07cdc4a3e8540544fd009c4311af7048122da60f2054c07ee4" } }, - { - "name": "Ropsten", - "parameters": { - "chain_id": 3, - "path": "m/44'/1'/0'/0/0", - "nonce": "0x0", - "gas_price": "0x4a817c800", - "gas_limit": "0x5208", - "value": "0x2540be400", - "to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98", - "tx_type": null, - "data": "" - }, - "result": { - "sig_v": 42, - "sig_r": "9d49a5c234a134bc56d00a7cf0c208c97d746f002c1fd3609b643eb8ef99d07d", - "sig_s": "3f064e133624cb59f8103fd5de76c089d8754e3da233a59d2ab2ca47fc306837" - } - }, - { - "name": "Rinkeby", - "parameters": { - "chain_id": 4, - "path": "m/44'/1'/0'/0/0", - "nonce": "0x0", - "gas_price": "0x4a817c800", - "gas_limit": "0x5208", - "value": "0x2540be400", - "to_address": "0x8eA7a3fccC211ED48b763b4164884DDbcF3b0A98", - "tx_type": null, - "data": "" - }, - "result": { - "sig_v": 43, - "sig_r": "79a9fd0391f027ed518f3d796a598bf33eef0fb30ef22568a140d674d6b0b76c", - "sig_s": "408cd459abafcdb7f2e415b269c85a308aad4c53e63c01d3431d3db6ab6292dd" - } - }, { "name": "ETC", "parameters": { diff --git a/common/tests/fixtures/solana/sign_tx.associated_token_account_program.json b/common/tests/fixtures/solana/sign_tx.associated_token_account_program.json index f067142b29..85eb7078cb 100644 --- a/common/tests/fixtures/solana/sign_tx.associated_token_account_program.json +++ b/common/tests/fixtures/solana/sign_tx.associated_token_account_program.json @@ -47,6 +47,52 @@ "expected_signature": "629daa88d10bca2315fe4176c323197a22c821026f7f6019cadbcf2769c5bb38ceef7652b5cba7e246a51f131f14fa8d776df63c50a1c4a09a3cf0bf2d446201" } }, + + { + "description": "Create Associated Token Account With Sysvar Rent included", + "parameters": { + "address": "m/44'/501'/0'/0'", + "construct": { + "version": null, + "header": { + "signers": 1, + "readonly_signers": 0, + "readonly_non_signers": 4 + }, + "accounts": [ + "14CCvQzQzHCVgZM3j9soPnXuJXh1RmCfwLVUcdfbZVBS", + "FUqrjRRtF1LiptdFqaFxipE8R3YfCE4k56xwm5n1piqX", + "11111111111111111111111111111111", + "6YuhWADZyAAxAaVKPm1G5N51RvDBXsnWo4SfsJ47wSoK", + "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL", + "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA", + "SysvarRent111111111111111111111111111111111" + ], + "blockhash": "2p4rYZAaFfV5Uk5ugdG5KPNty9Uda9B3b4gWB8qnNqak", + "instructions": [ + { + "program_index": 4, + "accounts": { + "funding_account": 0, + "associated_token_account": 1, + "wallet_address": 0, + "token_mint": 3, + "system_program": 2, + "spl_token": 5, + "sysvar_rent": 6 + }, + "data": { + "instruction_id": null + } + } + ], + "luts": [] + } + }, + "result": { + "expected_signature": "098276fc4770c80395e5dd2d3de24f14a6557a0078da95646558ce5dc91aebbdd961bf641dd1ad80ed09391b18f5dcc82157a240c689d86da225a26b9ac2b509" + } + }, { "description": "Create Associated Token Account Idempotent", "parameters": { diff --git a/common/tools/README.md b/common/tools/README.md index b0cf350e4f..748fc1f8a9 100644 --- a/common/tools/README.md +++ b/common/tools/README.md @@ -5,7 +5,7 @@ This directory contains mostly tools that can manipulate definitions in [defs/]( Tools are written with [Click](http://click.pocoo.org/6/), so you always get a help text if you use the `--help` option. -All tools require Python 3.6 or higher and a bunch of dependencies, listed in `requirements.txt`. +All tools require Python 3.8 or higher and a bunch of dependencies, listed in `requirements.txt`. You can install them all with `pip3 install -r requirements.txt`. ## Tools overview diff --git a/common/tools/coin_info.py b/common/tools/coin_info.py index a86b4bb129..58b3dcc812 100755 --- a/common/tools/coin_info.py +++ b/common/tools/coin_info.py @@ -26,32 +26,13 @@ DEFS_DIR = ROOT / "defs" -class SupportItemBool(TypedDict): - supported: dict[str, bool] - unsupported: dict[str, bool] - - class SupportItemVersion(TypedDict): supported: dict[str, str] unsupported: dict[str, str] -class SupportData(TypedDict): - connect: SupportItemBool - suite: SupportItemBool - t1b1: SupportItemVersion - t2t1: SupportItemVersion - t2b1: SupportItemVersion - - -class SupportInfoItem(TypedDict): - connect: bool - suite: bool - t1b1: Literal[False] | str - t2t1: Literal[False] | str - t2b1: Literal[False] | str - - +SupportData = Dict[str, SupportItemVersion] +SupportInfoItem = Dict[str, Literal[False] | str] SupportInfo = Dict[str, SupportInfoItem] @@ -449,8 +430,6 @@ def _load_fido_apps() -> FidoApps: # ====== support info ====== RELEASES_URL = "https://data.trezor.io/firmware/{}/releases.json" -MISSING_SUPPORT_MEANS_NO = ("connect", "suite") -VERSIONED_SUPPORT_INFO = ("T1B1", "T2T1", "T2B1") def get_support_data() -> SupportData: @@ -458,14 +437,18 @@ def get_support_data() -> SupportData: return load_json("support.json") +def get_models() -> list[str]: + """Get all models from `support.json`.""" + return list(get_support_data().keys()) + + def latest_releases() -> dict[str, Any]: """Get latest released firmware versions for all models""" if not requests: raise RuntimeError("requests library is required for getting release info") latest: dict[str, Any] = {} - for model in VERSIONED_SUPPORT_INFO: - # TODO: support new UPPERCASE model names in RELEASES_URL + for model in get_models(): url_model = model.lower() # need to be e.g. t1b1 for now releases = requests.get(RELEASES_URL.format(url_model)).json() latest[model] = max(tuple(r["version"]) for r in releases) @@ -492,8 +475,6 @@ def support_info_single(support_data: SupportData, coin: Coin) -> SupportInfoIte support_value: Any = False elif key in values["supported"]: support_value = values["supported"][key] - elif device in MISSING_SUPPORT_MEANS_NO: - support_value = False else: support_value = None support_info_item[device] = support_value diff --git a/common/tools/cointool.py b/common/tools/cointool.py index 9e0eb90269..9dc99f32dd 100755 --- a/common/tools/cointool.py +++ b/common/tools/cointool.py @@ -160,6 +160,7 @@ def render_file( ROOT=ROOT, **coins, **MAKO_FILTERS, + ALL_MODELS=coin_info.get_models(), ) dst.write_text(str(result)) src_stat = src.stat() diff --git a/common/tools/support.py b/common/tools/support.py index 01605f0c48..33628b8eae 100755 --- a/common/tools/support.py +++ b/common/tools/support.py @@ -11,6 +11,7 @@ import coin_info SUPPORT_INFO = coin_info.get_support_data() +MODELS = coin_info.get_models() VERSION_RE = re.compile(r"\d+.\d+.\d+") @@ -64,7 +65,7 @@ def set_unsupported(device, key, value): def print_support(coin): - def support_value(where, key, missing_means_no=False): + def support_value(where, key): if "supported" in where and key in where["supported"]: val = where["supported"][key] if val is True: @@ -76,8 +77,6 @@ def support_value(where, key, missing_means_no=False): elif "unsupported" in where and key in where["unsupported"]: val = where["unsupported"][key] return f"NO (reason: {val})" - elif missing_means_no: - return "NO" else: return "support info missing" @@ -86,8 +85,7 @@ def support_value(where, key, missing_means_no=False): if coin.get("duplicate"): print(" * DUPLICATE SYMBOL") for dev, where in SUPPORT_INFO.items(): - missing_means_no = dev in coin_info.MISSING_SUPPORT_MEANS_NO - print(" *", dev, ":", support_value(where, key, missing_means_no)) + print(" *", dev, ":", support_value(where, key)) # ====== validation functions ====== # @@ -111,12 +109,7 @@ def _check_value_version_soon(value): else: for key, value in supported.items(): try: - if device in coin_info.VERSIONED_SUPPORT_INFO: - _check_value_version_soon(value) - else: - if value is not True: - raise ValueError(f"only allowed is True, but found {value}") - + _check_value_version_soon(value) if key in unsupported: raise ValueError(f"{key} is both supported and unsupported") @@ -135,7 +128,7 @@ def _check_value_version_soon(value): def find_unsupported_coins(coins_dict): result = {} - for device in coin_info.VERSIONED_SUPPORT_INFO: + for device in MODELS: supported, unsupported = support_dicts(device) support_set = set(supported.keys()) support_set.update(unsupported.keys()) @@ -253,10 +246,8 @@ def release( key: val for key, val in (release.split("=") for release in releases) } for key in user_releases_dict: - if key not in coin_info.VERSIONED_SUPPORT_INFO: - raise click.ClickException( - f"Unknown device: {key} - allowed are: {coin_info.VERSIONED_SUPPORT_INFO}" - ) + if key not in MODELS: + raise click.ClickException(f"Unknown device: {key} - allowed are: {MODELS}") def bump_version(version_tuple: tuple[int]) -> str: version_list = list(version_tuple) @@ -267,7 +258,7 @@ def bump_version(version_tuple: tuple[int]) -> str: # Take version either from user or guess it from latest releases info device_release_version: dict[str, str] = {} - for device in coin_info.VERSIONED_SUPPORT_INFO: + for device in MODELS: if device in user_releases_dict: device_release_version[device] = user_releases_dict[device] else: @@ -355,15 +346,18 @@ def set_support_value(key, entries, reason): """Set a support info variable. Examples: - support.py set coin:BTC T1B1=1.10.5 T2T1=2.4.7 suite=yes connect=no - support.py set coin:LTC T1B1=yes connect= + support.py set coin:BTC T1B1=1.10.5 T2T1=2.4.7 T2B1=no - Setting a variable to "yes", "true" or "1" sets support to true. - Setting a variable to "no", "false" or "0" sets support to false. - (or null, in case of T1B1/T2T1) - Setting variable to empty ("T1B1=") will set to null, or clear the entry. Setting a variable to a particular version string (e.g., "2.4.7") will set that - particular version. + particular version as the earliest supported. + + Setting a variable to "yes", "true" or "1" sets support to the upcoming release, + as fetched via `coin_info.latest_releases()`. + + Setting a variable to "no", "false" or "0" sets support to false. You will need to + provide a reason for unsupporting, either via the `-r` option, or interactively. + + Setting variable to empty ("T1B1=") will set to null, or clear the entry. """ defs, _ = coin_info.coin_info_with_duplicates() coins = defs.as_dict() @@ -372,6 +366,11 @@ def set_support_value(key, entries, reason): click.echo("Use 'support.py show' to search for the right one.") sys.exit(1) + latest_releases = coin_info.latest_releases() + next_releases = { + k: (maj, min, pat + 1) for k, (maj, min, pat) in latest_releases.items() + } + for entry in entries: try: device, value = entry.split("=", maxsplit=1) @@ -383,11 +382,8 @@ def set_support_value(key, entries, reason): raise click.ClickException(f"unknown device: {device}") if value in ("yes", "true", "1"): - set_supported(device, key, True) + set_supported(device, key, next_releases[device]) elif value in ("no", "false", "0"): - if device in coin_info.MISSING_SUPPORT_MEANS_NO: - click.echo(f"Setting explicitly unsupported for {device}.") - click.echo(f"Perhaps you meant removing support, i.e., '{device}=' ?") if not reason: reason = click.prompt(f"Enter reason for not supporting on {device}:") set_unsupported(device, key, reason) diff --git a/core/.changelog.d/3370.added b/core/.changelog.d/3370.added deleted file mode 100644 index 20f7c86466..0000000000 --- a/core/.changelog.d/3370.added +++ /dev/null @@ -1 +0,0 @@ -Added basic support for STM32U5 diff --git a/core/.changelog.d/3520.fixed b/core/.changelog.d/3520.fixed deleted file mode 100644 index d5ee082337..0000000000 --- a/core/.changelog.d/3520.fixed +++ /dev/null @@ -1 +0,0 @@ -Translate also texts for PIN progress loaders. diff --git a/core/.changelog.d/3636.added b/core/.changelog.d/3636.added deleted file mode 100644 index 2d5938422a..0000000000 --- a/core/.changelog.d/3636.added +++ /dev/null @@ -1 +0,0 @@ -Added ability to request Shamir backups with any number of groups/shares. diff --git a/core/.changelog.d/3797.fixed b/core/.changelog.d/3797.fixed new file mode 100644 index 0000000000..a298e7f169 --- /dev/null +++ b/core/.changelog.d/3797.fixed @@ -0,0 +1 @@ +[T3T1] Redesigned FIDO2 UI. diff --git a/core/.changelog.d/3858.fixed b/core/.changelog.d/3858.fixed new file mode 100644 index 0000000000..303df6505c --- /dev/null +++ b/core/.changelog.d/3858.fixed @@ -0,0 +1 @@ +[T3T1] Improved ETH send flow. diff --git a/core/.changelog.d/3859.fixed b/core/.changelog.d/3859.fixed new file mode 100644 index 0000000000..06b0f82394 --- /dev/null +++ b/core/.changelog.d/3859.fixed @@ -0,0 +1 @@ +Fix persistent word when going to previous word during recovery process. diff --git a/core/.changelog.d/3940.added b/core/.changelog.d/3940.added deleted file mode 100644 index 3d19564b26..0000000000 --- a/core/.changelog.d/3940.added +++ /dev/null @@ -1 +0,0 @@ -[T2T1] Allow SD card hotswap based on production date diff --git a/core/.changelog.d/3990.fixed b/core/.changelog.d/3990.fixed new file mode 100644 index 0000000000..72e6165c36 --- /dev/null +++ b/core/.changelog.d/3990.fixed @@ -0,0 +1 @@ +[T2B1] Fix display orientation "south" diff --git a/core/.changelog.d/4047.added b/core/.changelog.d/4047.added new file mode 100644 index 0000000000..a2d3047eb4 --- /dev/null +++ b/core/.changelog.d/4047.added @@ -0,0 +1 @@ +Initial support for Italian and Portugese translations. diff --git a/core/.changelog.d/4054.added b/core/.changelog.d/4054.added new file mode 100644 index 0000000000..9abac987df --- /dev/null +++ b/core/.changelog.d/4054.added @@ -0,0 +1 @@ +[T3T1] Added reassuring screen when entering empty passphrase diff --git a/core/.changelog.d/4093.changed b/core/.changelog.d/4093.changed new file mode 100644 index 0000000000..ab2575938f --- /dev/null +++ b/core/.changelog.d/4093.changed @@ -0,0 +1 @@ +Changed prefix of public key returned by `get_ecdh_session_key` for curve25519. diff --git a/core/.changelog.d/4093.fixed b/core/.changelog.d/4093.fixed new file mode 100644 index 0000000000..0fa95d8866 --- /dev/null +++ b/core/.changelog.d/4093.fixed @@ -0,0 +1 @@ +Fixed SLIP-10 fingerprints for ed25519 and curve25519. diff --git a/core/.changelog.d/4099.added b/core/.changelog.d/4099.added new file mode 100644 index 0000000000..eacb4c6c02 --- /dev/null +++ b/core/.changelog.d/4099.added @@ -0,0 +1 @@ +Reduce the choices to select wordcount when unlocking repeated backup to 20 or 33. diff --git a/core/.changelog.d/4119.removed b/core/.changelog.d/4119.removed new file mode 100644 index 0000000000..f8c8d2759f --- /dev/null +++ b/core/.changelog.d/4119.removed @@ -0,0 +1 @@ +Removed display_random feature. diff --git a/core/.changelog.d/4142.fixed b/core/.changelog.d/4142.fixed new file mode 100644 index 0000000000..47a0ffd1f7 --- /dev/null +++ b/core/.changelog.d/4142.fixed @@ -0,0 +1 @@ +[T3T1] Added missing info about remaining shares in super-shamir recovery. diff --git a/core/.changelog.d/4151.changed b/core/.changelog.d/4151.changed new file mode 100644 index 0000000000..bad7fbfb38 --- /dev/null +++ b/core/.changelog.d/4151.changed @@ -0,0 +1 @@ +Renamed MATIC to POL, following a network upgrade. diff --git a/core/.changelog.d/4161.fixed b/core/.changelog.d/4161.fixed new file mode 100644 index 0000000000..4fc79ac044 --- /dev/null +++ b/core/.changelog.d/4161.fixed @@ -0,0 +1 @@ +[T2T1] Fix spending decred stake outputs. diff --git a/core/.changelog.d/4167.fixed b/core/.changelog.d/4167.fixed new file mode 100644 index 0000000000..cfa8a80b6d --- /dev/null +++ b/core/.changelog.d/4167.fixed @@ -0,0 +1 @@ +[T3T1] Fix swipe in ETH stake flow menu and address confirmation. diff --git a/core/.changelog.d/noissue.fixed b/core/.changelog.d/noissue.fixed new file mode 100644 index 0000000000..26a97edf5b --- /dev/null +++ b/core/.changelog.d/noissue.fixed @@ -0,0 +1 @@ +[T3T1] Improved ETH staking flow. diff --git a/core/CHANGELOG.T2B1.md b/core/CHANGELOG.T2B1.md index a58fbe7f72..43fd79d767 100644 --- a/core/CHANGELOG.T2B1.md +++ b/core/CHANGELOG.T2B1.md @@ -4,6 +4,54 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.1] (unreleased) + +### Added +- Improve precision of PIN timeout countdown. [#4000] + +### Fixed +- Solana: added support for deprecated AToken Create `rent_sysvar` argument. [#3976] + + +## [2.8.0] (9th July 2024) + +### Added +- Expose value of the Optiga SEC counter in `Features` message. + +### Changed +- Reworked PIN processing. + +### Removed +- CoSi functionality. [#3442] + +### Fixed +- Increase Optiga read timeout to avoid spurious RSODs. + + +## [2.7.2] (14th June 2024) + +### Fixed +- Fixed device freeze after setup. [#3925] +- Translation fixes. [#3916] + + +## [2.7.1] (internal release) + +### Added +- Added basic support for STM32U5. [#3370] +- Cardano: Added support for tagged sets in CBOR (tag 258). [#3496] +- Cardano: Added support for Conway certificates. [#3496] +- Added ability to request Shamir backups with any number of groups/shares. [#3636] +- Added support for repeated backups. [#3640] +- Support extendable backup flag in SLIP-39. + +### Changed +- Cardano: Increased max URL length to 128 bytes. [#3496] + +### Fixed +- Translate also texts for PIN progress loaders. [#3520] + + ## [2.7.0] (20th March 2024) ### Added @@ -834,10 +882,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#2937]: https://github.com/trezor/trezor-firmware/pull/2937 [#2955]: https://github.com/trezor/trezor-firmware/pull/2955 [#2989]: https://github.com/trezor/trezor-firmware/pull/2989 +[#3035]: https://github.com/trezor/trezor-firmware/pull/3035 [#3047]: https://github.com/trezor/trezor-firmware/pull/3047 [#3048]: https://github.com/trezor/trezor-firmware/pull/3048 [#3205]: https://github.com/trezor/trezor-firmware/pull/3205 [#3206]: https://github.com/trezor/trezor-firmware/pull/3206 +[#3208]: https://github.com/trezor/trezor-firmware/pull/3208 [#3216]: https://github.com/trezor/trezor-firmware/pull/3216 [#3218]: https://github.com/trezor/trezor-firmware/pull/3218 [#3237]: https://github.com/trezor/trezor-firmware/pull/3237 @@ -849,14 +899,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#3296]: https://github.com/trezor/trezor-firmware/pull/3296 [#3311]: https://github.com/trezor/trezor-firmware/pull/3311 [#3359]: https://github.com/trezor/trezor-firmware/pull/3359 +[#3370]: https://github.com/trezor/trezor-firmware/pull/3370 [#3377]: https://github.com/trezor/trezor-firmware/pull/3377 [#3411]: https://github.com/trezor/trezor-firmware/pull/3411 [#3424]: https://github.com/trezor/trezor-firmware/pull/3424 [#3434]: https://github.com/trezor/trezor-firmware/pull/3434 [#3440]: https://github.com/trezor/trezor-firmware/pull/3440 +[#3442]: https://github.com/trezor/trezor-firmware/pull/3442 [#3445]: https://github.com/trezor/trezor-firmware/pull/3445 [#3458]: https://github.com/trezor/trezor-firmware/pull/3458 [#3475]: https://github.com/trezor/trezor-firmware/pull/3475 [#3477]: https://github.com/trezor/trezor-firmware/pull/3477 +[#3496]: https://github.com/trezor/trezor-firmware/pull/3496 [#3517]: https://github.com/trezor/trezor-firmware/pull/3517 +[#3520]: https://github.com/trezor/trezor-firmware/pull/3520 [#3539]: https://github.com/trezor/trezor-firmware/pull/3539 +[#3636]: https://github.com/trezor/trezor-firmware/pull/3636 +[#3640]: https://github.com/trezor/trezor-firmware/pull/3640 +[#3728]: https://github.com/trezor/trezor-firmware/pull/3728 +[#3855]: https://github.com/trezor/trezor-firmware/pull/3855 +[#3885]: https://github.com/trezor/trezor-firmware/pull/3885 +[#3895]: https://github.com/trezor/trezor-firmware/pull/3895 +[#3896]: https://github.com/trezor/trezor-firmware/pull/3896 +[#3907]: https://github.com/trezor/trezor-firmware/pull/3907 +[#3911]: https://github.com/trezor/trezor-firmware/pull/3911 +[#3916]: https://github.com/trezor/trezor-firmware/pull/3916 +[#3917]: https://github.com/trezor/trezor-firmware/pull/3917 +[#3919]: https://github.com/trezor/trezor-firmware/pull/3919 +[#3922]: https://github.com/trezor/trezor-firmware/pull/3922 +[#3925]: https://github.com/trezor/trezor-firmware/pull/3925 +[#3940]: https://github.com/trezor/trezor-firmware/pull/3940 +[#3965]: https://github.com/trezor/trezor-firmware/pull/3965 +[#3969]: https://github.com/trezor/trezor-firmware/pull/3969 +[#3972]: https://github.com/trezor/trezor-firmware/pull/3972 +[#3976]: https://github.com/trezor/trezor-firmware/pull/3976 +[#3987]: https://github.com/trezor/trezor-firmware/pull/3987 +[#3992]: https://github.com/trezor/trezor-firmware/pull/3992 +[#4000]: https://github.com/trezor/trezor-firmware/pull/4000 +[#4006]: https://github.com/trezor/trezor-firmware/pull/4006 +[#4023]: https://github.com/trezor/trezor-firmware/pull/4023 +[#4030]: https://github.com/trezor/trezor-firmware/pull/4030 +[#4060]: https://github.com/trezor/trezor-firmware/pull/4060 +[#4063]: https://github.com/trezor/trezor-firmware/pull/4063 diff --git a/core/CHANGELOG.T2T1.md b/core/CHANGELOG.T2T1.md index b6caae302c..1fb8af53e2 100644 --- a/core/CHANGELOG.T2T1.md +++ b/core/CHANGELOG.T2T1.md @@ -4,6 +4,50 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.1] (21st August 2024) + +### Added +- Improve precision of PIN timeout countdown. [#4000] + +### Fixed +- Added a progress indicator for the formatting operation. [#3035] +- Solana: added support for deprecated AToken Create `rent_sysvar` argument. [#3976] + + +## [2.8.0] (9th July 2024) + +### Changed +- Reworked PIN processing. + +### Removed +- CoSi functionality. [#3442] + + +## [2.7.2] (14th June 2024) + +### Fixed +- Translation fixes. [#3916] + + +## [2.7.1] (internal release) + +### Added +- Added user adjustable brightness setting. [#3208] +- Added basic support for STM32U5. [#3370] +- Cardano: Added support for tagged sets in CBOR (tag 258). [#3496] +- Cardano: Added support for Conway certificates. [#3496] +- Added ability to request Shamir backups with any number of groups/shares. [#3636] +- Added support for repeated backups. [#3640] +- Allow SD card hotswap based on production date. [#3940] +- Support extendable backup flag in SLIP-39. + +### Changed +- Cardano: Increased max URL length to 128 bytes. [#3496] + +### Fixed +- Translate also texts for PIN progress loaders. [#3520] + + ## [2.7.0] (20th March 2024) ### Added @@ -832,10 +876,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#2937]: https://github.com/trezor/trezor-firmware/pull/2937 [#2955]: https://github.com/trezor/trezor-firmware/pull/2955 [#2989]: https://github.com/trezor/trezor-firmware/pull/2989 +[#3035]: https://github.com/trezor/trezor-firmware/pull/3035 [#3047]: https://github.com/trezor/trezor-firmware/pull/3047 [#3048]: https://github.com/trezor/trezor-firmware/pull/3048 [#3205]: https://github.com/trezor/trezor-firmware/pull/3205 [#3206]: https://github.com/trezor/trezor-firmware/pull/3206 +[#3208]: https://github.com/trezor/trezor-firmware/pull/3208 [#3216]: https://github.com/trezor/trezor-firmware/pull/3216 [#3218]: https://github.com/trezor/trezor-firmware/pull/3218 [#3237]: https://github.com/trezor/trezor-firmware/pull/3237 @@ -847,14 +893,46 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#3296]: https://github.com/trezor/trezor-firmware/pull/3296 [#3311]: https://github.com/trezor/trezor-firmware/pull/3311 [#3359]: https://github.com/trezor/trezor-firmware/pull/3359 +[#3370]: https://github.com/trezor/trezor-firmware/pull/3370 [#3377]: https://github.com/trezor/trezor-firmware/pull/3377 [#3411]: https://github.com/trezor/trezor-firmware/pull/3411 [#3424]: https://github.com/trezor/trezor-firmware/pull/3424 [#3434]: https://github.com/trezor/trezor-firmware/pull/3434 [#3440]: https://github.com/trezor/trezor-firmware/pull/3440 +[#3442]: https://github.com/trezor/trezor-firmware/pull/3442 [#3445]: https://github.com/trezor/trezor-firmware/pull/3445 [#3458]: https://github.com/trezor/trezor-firmware/pull/3458 [#3475]: https://github.com/trezor/trezor-firmware/pull/3475 [#3477]: https://github.com/trezor/trezor-firmware/pull/3477 +[#3496]: https://github.com/trezor/trezor-firmware/pull/3496 [#3517]: https://github.com/trezor/trezor-firmware/pull/3517 +[#3520]: https://github.com/trezor/trezor-firmware/pull/3520 [#3539]: https://github.com/trezor/trezor-firmware/pull/3539 +[#3636]: https://github.com/trezor/trezor-firmware/pull/3636 +[#3640]: https://github.com/trezor/trezor-firmware/pull/3640 +[#3728]: https://github.com/trezor/trezor-firmware/pull/3728 +[#3855]: https://github.com/trezor/trezor-firmware/pull/3855 +[#3885]: https://github.com/trezor/trezor-firmware/pull/3885 +[#3895]: https://github.com/trezor/trezor-firmware/pull/3895 +[#3896]: https://github.com/trezor/trezor-firmware/pull/3896 +[#3907]: https://github.com/trezor/trezor-firmware/pull/3907 +[#3911]: https://github.com/trezor/trezor-firmware/pull/3911 +[#3916]: https://github.com/trezor/trezor-firmware/pull/3916 +[#3917]: https://github.com/trezor/trezor-firmware/pull/3917 +[#3919]: https://github.com/trezor/trezor-firmware/pull/3919 +[#3922]: https://github.com/trezor/trezor-firmware/pull/3922 +[#3925]: https://github.com/trezor/trezor-firmware/pull/3925 +[#3940]: https://github.com/trezor/trezor-firmware/pull/3940 +[#3965]: https://github.com/trezor/trezor-firmware/pull/3965 +[#3969]: https://github.com/trezor/trezor-firmware/pull/3969 +[#3972]: https://github.com/trezor/trezor-firmware/pull/3972 +[#3976]: https://github.com/trezor/trezor-firmware/pull/3976 +[#3987]: https://github.com/trezor/trezor-firmware/pull/3987 +[#3990]: https://github.com/trezor/trezor-firmware/pull/3990 +[#3992]: https://github.com/trezor/trezor-firmware/pull/3992 +[#4000]: https://github.com/trezor/trezor-firmware/pull/4000 +[#4006]: https://github.com/trezor/trezor-firmware/pull/4006 +[#4023]: https://github.com/trezor/trezor-firmware/pull/4023 +[#4030]: https://github.com/trezor/trezor-firmware/pull/4030 +[#4060]: https://github.com/trezor/trezor-firmware/pull/4060 +[#4063]: https://github.com/trezor/trezor-firmware/pull/4063 diff --git a/core/CHANGELOG.T3T1.md b/core/CHANGELOG.T3T1.md new file mode 100644 index 0000000000..4148f5a663 --- /dev/null +++ b/core/CHANGELOG.T3T1.md @@ -0,0 +1,960 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [2.8.1] (21st August 2024) + +### Added +- Added PIN keyboard animation. [#3885] +- Added menu entry animation. [#3896] +- Improve precision of PIN timeout countdown. [#4000] +- New UI of confirming interaction-less firmware update. [#4030] + +### Changed +- Smoothened screen transitions by removing backlight fading. +- Improved resuming of interrupted animations. [#3987] +- Improve instruction screens during multi-share recovery process. [#3992] +- Improve share words swiping animation. [#4063] + +### Fixed +- Added a progress indicator for the formatting operation. [#3035] +- Improved screen brightness settings. [#3969] +- Improve touch layer precision. [#3972] +- Fix More info screen during multi-share backup creation. [#4006] +- Fixed title sometimes not fitting into result screen. [#4023] +- Adjusted detection of swipes: vertical swipes are preferred over horizontal swipes. [#4060] +- Solana: added support for deprecated AToken Create `rent_sysvar` argument. [#3976] + + +## [2.8.0] (9th July 2024) + +### Added +- Animated device label on homescreen/lockscreen. [#3895] +- Improved change homescreen flow. [#3907] +- Added word counter during wallet creation. [#3917] +- Expose value of the Optiga SEC counter in `Features` message. + +### Changed +- Reworked PIN processing. + +### Removed +- CoSi functionality. [#3442] + +### Fixed +- Fixed swipe back from address QR code screen. [#3919] +- Fixed device authenticity check. [#3922] +- Improve swipe behavior and animations. [#3965] +- Increase Optiga read timeout to avoid spurious RSODs. + + +## [2.7.2] (14th June 2024) + +### Fixed +- Fixed device authenticity check. [#3922] +- Wrong XPUB screen title. [#3911] +- Translation fixes. [#3916] + + +## [2.7.1] (internal release) + +### Added +- Added basic support for STM32U5. [#3370] +- Cardano: Added support for tagged sets in CBOR (tag 258). [#3496] +- Cardano: Added support for Conway certificates. [#3496] +- Added ability to request Shamir backups with any number of groups/shares. [#3636] +- Added support for repeated backups. [#3640] +- Support extendable backup flag in SLIP-39. +- User interface implementation. + +### Changed +- Cardano: Increased max URL length to 128 bytes. [#3496] +- Upgrade to bootloader 2.1.6. [#3855] + +### Fixed +- Translate also texts for PIN progress loaders. [#3520] + + +## [2.7.0] (20th March 2024) + +### Added +- Add translations capability. [#3206] +- Stellar: add support for `StellarClaimClaimableBalanceOp`. [#3434] +- Allow for going back to previous word in recovery process. [#3458] +- Clear sign ETH staking transactions on Everstake pool. [#3517] +- Send BIP-380 descriptor in GetPublicKey response. [#3539] + +### Changed +- Display descriptors for BTC Taproot public keys. [#3475] + +### Fixed +- Improved UI of multiple Solana instructions. [#3445] +- Solana multisig instruction warning will be displayed before instruction details are displayed. [#3445] +- Fixed Solana Memo instruction being unknown - it will now be recognized and displayed properly. [#3445] + + +## [2.6.4] (20th December 2023) + +### Added +- Added Solana support. [#3359] + +### Changed +- Always display Ethereum fees in Gwei. [#3246] + +### Fixed +- Fix invalid encoding of signatures from Optiga. [#3411] + + +## [2.6.3] (15th November 2023) + +### Added +- Support interaction-less upgrade. [#2919] +- Allowed non-zero address index in Cardano staking paths. [#3242] + +### Changed + +### Fixed + + +## [2.6.2] (internal release) + +### Added + + +## [2.6.1] (internal release) + +### Added +- QR code display when exporting XPUBs. [#3047] +- Added hw model field to all vendor headers. [#3048] +- Added firmware update without interaction. [#3205] +- Split builds of different parts to use simple util.s assembler, while FW+bootloader use interconnected ones. [#3205] +- Add support for address chunkification in Receive and Sign flow. [#3237] + +### Changed +- Update to MicroPython 1.19.1. [#2341] +- Introduce multisig warning to BTC receive flow. [#2937] +- Introduce multiple account warning to BTC send flow. [#2937] + +### Removed +- MUE coin support. [#3216] + +### Fixed + + +## [2.6.0] (19th April 2023) + +### Added +- Signed Ethereum network and token definitions from host. [#15] +- CoSi collective signatures on Model T. [#450] +- Support Ledger Live legacy derivation path `m/44'/coin_type'/0'/account`. [#1749] +- Updated bootloader to 2.1.0. [#1901] +- Show source account path in BTC signing. [#2151] +- Show path for internal outputs in BTC signing. [#2152] +- Add model info to image and check when installing bootloader, prevent bootloader downgrade. [#2623] +- Allow proposed Casa m/45' multisig paths for Bitcoin and Ethereum. [#2682] +- Support for external reward addresses in Cardano CIP-36 registrations. [#2692] +- Add address confirmation screen to EIP712 signing flow. [#2818] +- Add the possibility of rebooting the device into bootloader mode. [#2841] + +### Changed +- Switched to redesigned, Rust-based user interface. [#1922] +- Ignore channel ID in U2F. [#2205] +- Micropython code optimizations to make the code take less flash space. [#2525] +- CPU Frequency increased to 180 MHz. [#2587] +- Fixed display blinking by increasing backlight PWM frequency. [#2595] +- Updated FAT FS library to R0.15. [#2611] +- Auto-lock timer is no longer restarted by USB messages, only touch screen activity. [#2651] +- Updated UI and terminology in Cardano CIP-36 registrations. [#2692] +- Ethereum's EIP-712 signing no longer restricts the maximum field size to 1024 bytes. [#2746] +- Force basic attestation in FIDO2 for google.com. [#2834] + +### Fixed +- Enable Trezor to work as a FIDO2 authenticator for Apple. [#2784] +- Fix RNG for bootloader and make insecure PRNG opt-in, not opt-out. [#2899] + +### Security +- Match and validate script type of change-outputs in Bitcoin signing. + + +## [2.5.3] (16th November 2022) + +### Added +- Optimize touch controller communication. [#262] +- Add SLIP-0025 CoinJoin accounts. [#2289] +- Show red error header when USB data pins are not connected. [#2366] +- Add support for Zcash unified addresses. [#2398] +- Using hardware acceleration (dma2d) for rendering. [#2414] +- Add stack overflow detection. [#2427] +- Show fee rate when replacing transaction. [#2442] +- Support SetBusy message. [#2445] +- Add serialize option to SignTx. [#2507] +- Support for Cardano CIP-36 governance registration format. [#2561] +- Implement CoinJoin requests. [#2577] + +### Changed +- Extend decimals of fee rate to 2 digits. [#2486] +- Display only sat instead of sat BTC. [#2487] +- Remove old BulletProof code from Monero. [#2570] + +### Fixed +- Fix sending XMR transaction to an integrated address. [#2213] +- Fix XMR primary address display. [#2453] + + +## [2.5.2] (17th August 2022) + +### Added +- Add model R emulator [#2230] +- Add support for Monero HF15 features. [#2232] +- Add basic Trezor Model R hardware support [#2243] +- Show the fee rate on the signing confirmation screen. [#2249] +- Jump and stay in bootloader from firmware through SVC call reverse trampoline. [#2284] +- Expose raw pixel access to Rust [#2297] +- Add RGB LED for Model R [#2300] +- Boardloader capabilities structure [#2324] +- Support for Cardano Babbage era transaction items [#2354] +- Add "Show All"/"Show Simple" choice to Cardano transaction signing [#2355] +- Documentation for embedded C+Rust debugging [#2380] +- Show thousands separator when displaying large amounts. [#2394] + +### Changed +- Refactor and cleanup of Monero code. [#642] +- Remove power-down power-up cycle from touch controller initialization in firmware [#2130] +- Updated secp256k1-zkp. [#2261] +- Cardano internal refactors [#2313] +- Allow Cardano's `required_signers` in ordinary and multisig transactions + Allow Cardano's `datum_hash` in non-script outputs [#2354] + +### Removed +- Removed support for obsolete Monero hardfork 12 and below [#642] +- Remove firmware dumping capability. [#2433] + +### Fixed +- _(Emulator)_ Emulator window will always react to shutdown events, even while waiting for USB packets. [#973] +- Ensure correct order when verifying external inputs in Bitcoin signing. [#2415] +- Fix Decred transaction weight calculation. [#2422] + + +## 2.5.1 [18th May 2022] + +### Added +- Support Bitcoin payment requests. [#1430] +- Show "signature is valid" dialog when VerifyMessage succeeds. [#1880] +- Support ownership proofs for Taproot addresses. [#1944] +- Add extra check for Taproot scripts validity. [#2077] +- Support Electrum signatures in VerifyMessage. [#2100] +- Support Cardano Alonzo-era transactions (Plutus). [#2114] +- Support unverified external inputs. [#2144] +- Support Zcash version 5 transaction format [#2166] +- Add firmware hashing functionality. [#2239] + +### Changed +- Ensure input's script type and path match the scriptPubKey. [#1018] +- Automatically choose best size and encoding for QR codes. [#1751] +- Bitcoin bech32 addresses are encoded in lower-case for QR codes. [#1751] +- Full type-checking for Python code (except Monero app). [#1939] +- \[debuglink] Do not wait for screen refresh when _disabling_ layout watching. [#2135] + +### Removed +- GAME, NIX and POLIS support. [#2181] + +### Fixed +- EIP-1559 transaction correctly show final Hold to Confirm screen. [#2020] +- Fix sighash computation in proofs of ownership. [#2034] +- Fix domain-only EIP-712 hashes (i.e. when `primaryType`=`EIP712Domain`). [#2036] +- Support EIP-712 messages where a struct type is only used as an array element. [#2167] + +### Security +- Fix a coin loss vulnerability related to replacement transactions with multisig inputs and unverified external inputs. + +### Incompatible changes +- Trezor will refuse to sign UTXOs that do not match the provided derivation path (e.g., transactions belonging to a different wallet, or synthetic transaction inputs). [#1018] + + +## 2.4.3 [8th December 2021] + +### Added +- Convert timestamps to human-readable dates and times. [#741] +- Support no_script_type option in SignMessage. [#1586] +- Show address confirmation in SignMessage. [#1586] +- Support pre-signed external Taproot inputs in Bitcoin. [#1656] +- Show warning dialog in SignMessage if a non-standard path is used. [#1656] +- Support spending from Taproot UTXOs. [#1656] +- Support GetAddress for Taproot addresses. [#1656] +- Support sending to Taproot addresses. [#1656] +- Support replacement transactions with Taproot inputs in Bitcoin. [#1656] +- Support of BIP-340 Schnorr signatures (using secp256k1-zkp). [#1678] +- Support for Taproot descriptors. [#1710] +- Ethereum: support 64-bit chain IDs. [#1771] +- Support for Cardano multi-sig transactions, token minting, script addresses, multi-sig keys, minting keys and native script verification. [#1772] +- For compatibility with other Cardano implementations, it is now possible to specify which Cardano derivation type is used. [#1783] +- Full type-checking for Ethereum app. [#1794] +- Ethereum - support for EIP712 - signing typed data. [#1835] +- Stellar: add support for StellarManageBuyOfferOp and StellarPathPaymentStrictSendOp. [#1838] +- Add script_pubkey field to TxInput message. [#1857] + +### Changed +- Cardano root is derived together with the normal master secret. [#1231] +- Update QR-code-generator library version. [#1639] +- Faster ECDSA signing and verification (using secp256k1-zkp). [#1678] +- Most Stellar fields are now required on protobuf level. [#1755] +- Type-checking enabled for apps.stellar. [#1755] +- Updated micropython to version 1.17. [#1789] +- Errors from protobuf decoding are now more expressive. [#1811] + +### Removed +- Disable previous transaction streaming in Bitcoin if all internal inputs are Taproot. [#1656] +- Remove BELL, ZNY support. [#1872] + +### Fixed +- Remove altcoin message definitions from bitcoin-only build. [#1633] +- Ethereum: make it optional to view the entire data field when signing transaction. [#1819] + +### Security +- Ensure that the user is always warned about non-standard paths. +- Avoid accidental build with broken stack protector. [#1642] + +### Incompatible changes +- Session must be configured with Initialize(derive_cardano=True), otherwise Cardano functions will fail. [#1231] +- Timebounds must be set for a Stellar transaction. [#1755] +- Cardano derivation type must be specified for all Cardano functions. [#1783] +- Ethereum non-EIP-155 cross-chain signing is no longer supported. [#1794] +- Stellar: rename StellarManageOfferOp to StellarManageSellOfferOp, StellarPathPaymentOp to StellarPathPaymentStrictReceiveOp and StellarCreatePassiveOfferOp to StellarCreatePassiveSellOfferOp. [#1838] + + +## 2.4.2 [16th September 2021] + +### Added +- [emulator] Added option to dump detailed Micropython memory layout [#1557] +- Support for Ethereum EIP1559 transactions [#1604] +- Re-enabled Firo support [#1767] + +### Changed +- Converted all remaining code to common layouts. [#1545] +- Memory optimization of BTC signing and CBOR decoding. [#1581] +- Cardano transaction parameters are now streamed into the device one by one instead of being sent as one large object [#1683] +- Thanks to transaction streaming, Cardano now supports larger transactions (tested with 62kB transactions, but supposedly even larger transactions are supported) [#1683] +- Refactor RLP codec for better clarity and some small memory savings. [#1704] +- Refer to `m/48'/...` multisig derivation paths as BIP-48 instead of Purpose48. [#1744] + +### Removed +- Removed support for Lisk [#1765] + +### Fixed +- Disable TT features (SD card, SBU, FAT) for T1 build. [#1163] +- It is no longer possible to sign Cardano transactions containing paths belonging to multiple accounts (except for Byron to Shelley migration) [#1683] +- Add new rpId to Binance's FIDO definition. [#1705] +- Don't use format strings in keyctl-proxy [#1707] +- Properly respond to USB events while on a paginated screen. [#1708] + +### Incompatible changes +- Due to transaction streaming in Cardano, it isn't possible to return the whole serialized transaction anymore. Instead the transaction hash, transaction witnesses and auxiliary data supplement are returned and the serialized transaction needs to be assembled by the client. [#1683] + + +## 2.4.1 [14th July 2021] + +### Added +- ButtonRequest for multi-page views contains number of pages. [#1671] + +### Changed +- Converted altcoin apps to common layout code. [#1538] +- Reimplement protobuf codec and library in Rust [#1541] +- Cardano: Reintroduce maximum transaction output size limitation [#1606] +- Cardano: Improve address validation and decouple it from address derivation [#1606] +- Cardano: Remove sorting of policies, assets and withdrawals. Rather add them to the transaction in the order they arrived in. [#1672] +- Cardano: Forbid withdrawals with the same path in a single transaction [#1672] + +### Removed +- Removed support for Firo [#1647] +- Removed support for Hatch [#1650] + +### Fixed +- Unify Features.revision reporting with legacy [#1620] +- Fix red screen on shutdown. [#1658] +- Empty passphrase is properly cached in Cardano functions [#1659] + +### Security +- Ensure that all testnet coins use SLIP-44 coin type 1. +- Disable all testnet coins from accessing Bitcoin paths. +- Restrict BIP-45 paths to Bitcoin and coins with strong replay protection. +- Fix operation source account encoding in Stellar. + + +## 2.4.0 [9th June 2021] + +### Added +- Decred staking. [#1249] +- Locking the device by holding finger on the homescreen for 2.5 seconds. [#1404] +- Public key to ECDHSessionKey. [#1518] +- Rust FFI for MicroPython. [#1540] + +### Changed +- Support PIN of unlimited length. [#1167] +- Allow decreasing the output value in RBF transactions. [#1491] +- Cardano: Allow stake pool registrations with zero margin. [#1502] +- Cardano: Assets are now shown as CIP-0014. [#1510] +- Random delays use ChaCha-based DRBG instead of HMAC-DRBG. [#1554] +- Reduce memory fragmentation by clearing memory after every workflow. [#1565] +- Update some FIDO icons. [#1456] + +### Fixed +- Import errors on T1 startup. [#24] +- Improve wording when showing multisig XPUBs. [#1431] + + +## 2.3.6 [15th February 2021] + +### Added +- Compatibility paths for Unchained Capital. [#1467] + +## 2.3.5 [10th February 2021] + +### Added +- CoinJoin preauthorization and signing flow. [#1053] +- Value of the `safety-checks` setting to the `Features` message. [#1193] +- ERC20 tokens show contract address for confirmation. Unknown ERC20 tokens show wei amount. [#800] +- Replacement transaction signing for replace-by-fee and PayJoin. [#1292] +- Support for Output Descriptors export. [#1363] +- Paginated display for signing/verifying long messages. [#1271] +- Show Ypub/Zpub correctly for multisig GetAddress. [#1415] +- Show amounts in mBTC, uBTC and sat denominations. [#1369] + +### Changed +- The `safety-checks` setting gained new possible value `PromptTemporarily` which overrides safety checks until device reboot. [#1133] +- Protobuf codec now enforces `required` fields and pre-fills default values. [#379] +- `TxAck` messages are now decoded into "polymorphic" subtypes instead of the common `TxAck` type. +- Bump nanopb dependency to 0.4.3. [#1105] +- BIP-32 paths must now match a pre-defined path schema to be considered valid. [#1184] +- Minimum auto-lock delay to 1 minute. The former value of 10 seconds still applies for debug builds. [#1351] +- It is again possible to sign for Ethereum clones that are not officially supported. [#1335] +- Bump nanopb dependency to 0.4.4. [#1402] +- Automatic breaking text on whitespace. [#1384] +- Introduced limit of 32 characters for device label. [#1399] + +### Deprecated + +### Removed +- PIVX support +- dropped debug-only `DebugLinkShowText` functionality + +### Fixed +- Path warning is not shown on `GetAddress(show_display=False)` call. [#1206] +- Settings are also erased from RAM when device is wiped. [#1322] + +### Security + +## 2.3.4 [7th October 2020] + +### Added +- Support for the upcoming Monero hard fork. [#1246] + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### Security + + +## 2.3.3 [2nd September 2020] + +### Added +- Running the frozen version of the emulator doesn't need arguments. [#1115] +- XVG support. [#1165] +- Hard limit on transaction fees. Can be disabled using `safety-checks`. [#1087] + +### Changed +- Print inverted question mark for non-printable characters. +- Remove pre-fill bar from text rendering functions. [#1173] +- Display coin name when signing or verifying messages. [#1159] +- Allow spending coins from Bitcoin paths if the coin has implemented strong replay protection via `SIGHASH_FORKID`. [#1188] + +### Deprecated + +### Removed +- Remove ETP, GIN, PTC, ZEL support. +- Drop support for signing Zcash v3 transactions. [#982] + +### Fixed +- CRW addresses are properly generated. [#1139] +- Fix boot loop after uploading invalid homescreen. [#1118] +- Allow 49/x not 49/x' for Casa. [#1190] +- Make sure Homescreen is properly initialized. [#1095] + +### Security +- Show non-empty passphrase on device when it was entered on host. +- Show warning if nLockTime is set but ineffective due to all nSequence values being 0xffffffff. + +## 2.3.2 [5th August 2020] + +### Added +- Soft lock. [#958] +- Auto lock. [#1027] +- Dedicated `initialized` field in storage. +- Support EXTERNAL transaction inputs with a SLIP-0019 proof of ownership. [#1052] +- Support pre-signed EXTERNAL transaction inputs. +- Support multiple change-outputs. [#1098] +- New option `safety-checks` allows overriding "forbidden key path" errors. [#1126] +- Support for Cardano Shelley. [#948] + +### Changed +- `Features.pin_cached` renamed to `unlocked`. +- Forbid all settings if the device is not yet initialized. [#1056] +- Rewrite USB codec and Protobuf decoder to be more memory-efficient. [#1089] +- Allow compatibility namespaces for Casa and Green Address. + +### Deprecated +- Deprecate `overwintered` field in `SignTx` and `TxAck`. + +### Removed +- Generated protobuf classes now do not contain deprecated fields. + +### Fixed +- Fix cancel icon in PIN dialog. [#1042] +- Fix repaint bug in QR code rendering. [#1067] +- Fix QR code overlapping in Monero address. monero-gui#2960, [#1074] +- Re-introduce ability to spend pre-Overwinter UTXO on Zcash-like coins. [#1030] + +## 2.3.1 [June 2020] + +### Changed +- Refactor Bitcoin signing +- Refactor Keychain into a decorator + +### Security +- Stream previous tx also for Segwit inputs + +## 2.3.0 [April 2020] + +### Added +- Cache up to 10 sessions (passphrases) +- SD card protection +- Show xpubs with multisig get_address +- Introduce FatFS (version 0.14) +- Support Ed25519 in FIDO2 + +### Changed +- Passphrase redesign +- Upgrade MicroPython to 1.12 + +### Fixed +- Properly limit passphrase to 50 bytes and not 50 characters +- Monero: add confirmation dialog for unlock_time + +## 2.2.0 [January 2020] + +### Added +- Add feature to retrieve the next U2F counter. +- Wipe code. +- Add screen for time bounds in Stellar. + +### Fixed +- Fix continuous display blinking with Android in U2F. +- U2F UX improvements. + +### Changed +- Rework Recovery persistence internally. + +### Removed +- Remove unused ButtonRequest.data field. +- Disallow changing of settings via dry-run recovery. + +## 2.1.8 [November 2019] + +### Added +- Support Tezos 005-BABYLON hardfork. +- Show XPUBs in GetAddress for multisig. + +### Security +- Security improvements. + +## 2.1.7 [October 2019] + +### Fixed +- Fix low memory issue. + +## 2.1.6 [October 2019] + +### Added +- Super Shamir. +- FIDO2. +- FIDO2 credential management via trezorctl. +- BackupType in Features. + +### Changed +- Refactor Shamir related codebase. + +### Fixed +- Fix storage keys module visibility bug (6ad329) introduced in 2.1.3 (46e4c0) which was breaking upgrades. + +## 2.1.5 [September 2019] + +### Added +- Binance Coin support. +- Introduce Features.Capabilities. + +### Fixed +- Fix for sluggish U2F authentication when using Shamir. +- Fix UI for Shamir with 33 words. +- Fix Wanchain signing. + +## 2.1.4 [August 2019 hotfix] + +### Fixed +- Shamir Backup reset device hotfix. + +## 2.1.3 [August 2019] + +### Added +- Shamir Backup with Recovery persistence. + +### Fixed +- Touchscreen freeze fix. +- Fix display of non-divisible OMNI amounts. + +## 2.1.2 [unreleased] + +### Added +- Shamir Backup feature preview. + +## 2.1.1 [June 2019] + +### Added +- EOS support. +- Set screen rotation via user setting. +- Display non-zero locktime values. + +### Changed +- Don't rotate the screen via swipe gesture. +- More strict path validations. + +### Fixed +- Hotfix for touchscreen freeze. +- Monero UI fixes. +- Speed and memory optimizations. + +## 2.1.0 [March 2019] + +### Added +- New coins: ATS, AXE, FLO, GIN, KMD, NIX, PIVX, REOSC, XPM, XSN, ZCL. +- New ETH tokens. + +### Fixed +- Ripple, Stellar, Cardano and NEM fixes. + +### Changed +- Included bootloader 2.0.3. + +### Security +- Security improvements. +- Upgraded to new storage format. + +## 2.0.10 [December 2018] + +### Added +- Add support for OMNI layer: OMNI/MAID/USDT. +- Add support for new coins: BTX, CPC, GAME, RVN. +- Add support for new Ethereum tokens. + +### Changed +- Included bootloader 2.0.2. + +### Fixed +- Fix Monero payment ID computation. +- Fix issue with touch screen and flickering. + +## 2.0.9 [November 2018] + +### Fixed +- Small Monero and Segwit bugfixes. + +## 2.0.8 [October 2018] + +### Added +- Monero support. +- Cardano support. +- Stellar support. +- Ripple support. +- Tezos support. +- Decred support. +- Groestlcoin support. +- Zencash support. +- Zcash sapling hardfork support. +- Implemented seedless setup. + +## 2.0.7 [June 2018] + +### Added +- Bitcoin Cash cashaddr support. +- Zcash Overwinter hardfork support. +- NEM support. +- Lisk support. +- Show warning on home screen if PIN is not set. +- Support for new coins (BTCP, FUJI, VTC, VIA, XZC). +- Support for new Ethereum networks (EOSC, ETHS, ELLA, CTL, EGEM, WAN). +- Support for 500+ new Ethereum tokens. + +## 2.0.6 [March 2018] + +### Added +- Add special characters to passphrase keyboard. + +### Fixed +- Fix layout for Ethereum transactions. +- Fix public key generation for SSH and GPG. + +## 2.0.5 [March 2018] + +### Added +- First public release. + +[#15]: https://github.com/trezor/trezor-firmware/pull/15 +[#24]: https://github.com/trezor/trezor-firmware/pull/24 +[#262]: https://github.com/trezor/trezor-firmware/pull/262 +[#379]: https://github.com/trezor/trezor-firmware/pull/379 +[#450]: https://github.com/trezor/trezor-firmware/pull/450 +[#642]: https://github.com/trezor/trezor-firmware/pull/642 +[#741]: https://github.com/trezor/trezor-firmware/pull/741 +[#800]: https://github.com/trezor/trezor-firmware/pull/800 +[#948]: https://github.com/trezor/trezor-firmware/pull/948 +[#958]: https://github.com/trezor/trezor-firmware/pull/958 +[#973]: https://github.com/trezor/trezor-firmware/pull/973 +[#982]: https://github.com/trezor/trezor-firmware/pull/982 +[#1018]: https://github.com/trezor/trezor-firmware/pull/1018 +[#1027]: https://github.com/trezor/trezor-firmware/pull/1027 +[#1030]: https://github.com/trezor/trezor-firmware/pull/1030 +[#1042]: https://github.com/trezor/trezor-firmware/pull/1042 +[#1049]: https://github.com/trezor/trezor-firmware/pull/1049 +[#1052]: https://github.com/trezor/trezor-firmware/pull/1052 +[#1053]: https://github.com/trezor/trezor-firmware/pull/1053 +[#1056]: https://github.com/trezor/trezor-firmware/pull/1056 +[#1067]: https://github.com/trezor/trezor-firmware/pull/1067 +[#1074]: https://github.com/trezor/trezor-firmware/pull/1074 +[#1087]: https://github.com/trezor/trezor-firmware/pull/1087 +[#1089]: https://github.com/trezor/trezor-firmware/pull/1089 +[#1095]: https://github.com/trezor/trezor-firmware/pull/1095 +[#1098]: https://github.com/trezor/trezor-firmware/pull/1098 +[#1105]: https://github.com/trezor/trezor-firmware/pull/1105 +[#1115]: https://github.com/trezor/trezor-firmware/pull/1115 +[#1118]: https://github.com/trezor/trezor-firmware/pull/1118 +[#1126]: https://github.com/trezor/trezor-firmware/pull/1126 +[#1133]: https://github.com/trezor/trezor-firmware/pull/1133 +[#1139]: https://github.com/trezor/trezor-firmware/pull/1139 +[#1159]: https://github.com/trezor/trezor-firmware/pull/1159 +[#1163]: https://github.com/trezor/trezor-firmware/pull/1163 +[#1165]: https://github.com/trezor/trezor-firmware/pull/1165 +[#1167]: https://github.com/trezor/trezor-firmware/pull/1167 +[#1173]: https://github.com/trezor/trezor-firmware/pull/1173 +[#1184]: https://github.com/trezor/trezor-firmware/pull/1184 +[#1188]: https://github.com/trezor/trezor-firmware/pull/1188 +[#1190]: https://github.com/trezor/trezor-firmware/pull/1190 +[#1193]: https://github.com/trezor/trezor-firmware/pull/1193 +[#1206]: https://github.com/trezor/trezor-firmware/pull/1206 +[#1231]: https://github.com/trezor/trezor-firmware/pull/1231 +[#1246]: https://github.com/trezor/trezor-firmware/pull/1246 +[#1249]: https://github.com/trezor/trezor-firmware/pull/1249 +[#1271]: https://github.com/trezor/trezor-firmware/pull/1271 +[#1292]: https://github.com/trezor/trezor-firmware/pull/1292 +[#1322]: https://github.com/trezor/trezor-firmware/pull/1322 +[#1335]: https://github.com/trezor/trezor-firmware/pull/1335 +[#1351]: https://github.com/trezor/trezor-firmware/pull/1351 +[#1363]: https://github.com/trezor/trezor-firmware/pull/1363 +[#1369]: https://github.com/trezor/trezor-firmware/pull/1369 +[#1384]: https://github.com/trezor/trezor-firmware/pull/1384 +[#1399]: https://github.com/trezor/trezor-firmware/pull/1399 +[#1402]: https://github.com/trezor/trezor-firmware/pull/1402 +[#1404]: https://github.com/trezor/trezor-firmware/pull/1404 +[#1415]: https://github.com/trezor/trezor-firmware/pull/1415 +[#1430]: https://github.com/trezor/trezor-firmware/pull/1430 +[#1431]: https://github.com/trezor/trezor-firmware/pull/1431 +[#1456]: https://github.com/trezor/trezor-firmware/pull/1456 +[#1467]: https://github.com/trezor/trezor-firmware/pull/1467 +[#1491]: https://github.com/trezor/trezor-firmware/pull/1491 +[#1502]: https://github.com/trezor/trezor-firmware/pull/1502 +[#1510]: https://github.com/trezor/trezor-firmware/pull/1510 +[#1518]: https://github.com/trezor/trezor-firmware/pull/1518 +[#1538]: https://github.com/trezor/trezor-firmware/pull/1538 +[#1540]: https://github.com/trezor/trezor-firmware/pull/1540 +[#1541]: https://github.com/trezor/trezor-firmware/pull/1541 +[#1545]: https://github.com/trezor/trezor-firmware/pull/1545 +[#1554]: https://github.com/trezor/trezor-firmware/pull/1554 +[#1557]: https://github.com/trezor/trezor-firmware/pull/1557 +[#1565]: https://github.com/trezor/trezor-firmware/pull/1565 +[#1581]: https://github.com/trezor/trezor-firmware/pull/1581 +[#1586]: https://github.com/trezor/trezor-firmware/pull/1586 +[#1604]: https://github.com/trezor/trezor-firmware/pull/1604 +[#1606]: https://github.com/trezor/trezor-firmware/pull/1606 +[#1620]: https://github.com/trezor/trezor-firmware/pull/1620 +[#1633]: https://github.com/trezor/trezor-firmware/pull/1633 +[#1639]: https://github.com/trezor/trezor-firmware/pull/1639 +[#1642]: https://github.com/trezor/trezor-firmware/pull/1642 +[#1647]: https://github.com/trezor/trezor-firmware/pull/1647 +[#1650]: https://github.com/trezor/trezor-firmware/pull/1650 +[#1656]: https://github.com/trezor/trezor-firmware/pull/1656 +[#1658]: https://github.com/trezor/trezor-firmware/pull/1658 +[#1659]: https://github.com/trezor/trezor-firmware/pull/1659 +[#1671]: https://github.com/trezor/trezor-firmware/pull/1671 +[#1672]: https://github.com/trezor/trezor-firmware/pull/1672 +[#1678]: https://github.com/trezor/trezor-firmware/pull/1678 +[#1683]: https://github.com/trezor/trezor-firmware/pull/1683 +[#1704]: https://github.com/trezor/trezor-firmware/pull/1704 +[#1705]: https://github.com/trezor/trezor-firmware/pull/1705 +[#1707]: https://github.com/trezor/trezor-firmware/pull/1707 +[#1708]: https://github.com/trezor/trezor-firmware/pull/1708 +[#1710]: https://github.com/trezor/trezor-firmware/pull/1710 +[#1744]: https://github.com/trezor/trezor-firmware/pull/1744 +[#1749]: https://github.com/trezor/trezor-firmware/pull/1749 +[#1751]: https://github.com/trezor/trezor-firmware/pull/1751 +[#1755]: https://github.com/trezor/trezor-firmware/pull/1755 +[#1765]: https://github.com/trezor/trezor-firmware/pull/1765 +[#1767]: https://github.com/trezor/trezor-firmware/pull/1767 +[#1771]: https://github.com/trezor/trezor-firmware/pull/1771 +[#1772]: https://github.com/trezor/trezor-firmware/pull/1772 +[#1783]: https://github.com/trezor/trezor-firmware/pull/1783 +[#1789]: https://github.com/trezor/trezor-firmware/pull/1789 +[#1794]: https://github.com/trezor/trezor-firmware/pull/1794 +[#1811]: https://github.com/trezor/trezor-firmware/pull/1811 +[#1819]: https://github.com/trezor/trezor-firmware/pull/1819 +[#1835]: https://github.com/trezor/trezor-firmware/pull/1835 +[#1838]: https://github.com/trezor/trezor-firmware/pull/1838 +[#1857]: https://github.com/trezor/trezor-firmware/pull/1857 +[#1872]: https://github.com/trezor/trezor-firmware/pull/1872 +[#1880]: https://github.com/trezor/trezor-firmware/pull/1880 +[#1901]: https://github.com/trezor/trezor-firmware/pull/1901 +[#1922]: https://github.com/trezor/trezor-firmware/pull/1922 +[#1939]: https://github.com/trezor/trezor-firmware/pull/1939 +[#1944]: https://github.com/trezor/trezor-firmware/pull/1944 +[#2020]: https://github.com/trezor/trezor-firmware/pull/2020 +[#2034]: https://github.com/trezor/trezor-firmware/pull/2034 +[#2036]: https://github.com/trezor/trezor-firmware/pull/2036 +[#2077]: https://github.com/trezor/trezor-firmware/pull/2077 +[#2100]: https://github.com/trezor/trezor-firmware/pull/2100 +[#2114]: https://github.com/trezor/trezor-firmware/pull/2114 +[#2130]: https://github.com/trezor/trezor-firmware/pull/2130 +[#2135]: https://github.com/trezor/trezor-firmware/pull/2135 +[#2144]: https://github.com/trezor/trezor-firmware/pull/2144 +[#2151]: https://github.com/trezor/trezor-firmware/pull/2151 +[#2152]: https://github.com/trezor/trezor-firmware/pull/2152 +[#2161]: https://github.com/trezor/trezor-firmware/pull/2161 +[#2166]: https://github.com/trezor/trezor-firmware/pull/2166 +[#2167]: https://github.com/trezor/trezor-firmware/pull/2167 +[#2181]: https://github.com/trezor/trezor-firmware/pull/2181 +[#2205]: https://github.com/trezor/trezor-firmware/pull/2205 +[#2213]: https://github.com/trezor/trezor-firmware/pull/2213 +[#2230]: https://github.com/trezor/trezor-firmware/pull/2230 +[#2232]: https://github.com/trezor/trezor-firmware/pull/2232 +[#2239]: https://github.com/trezor/trezor-firmware/pull/2239 +[#2243]: https://github.com/trezor/trezor-firmware/pull/2243 +[#2249]: https://github.com/trezor/trezor-firmware/pull/2249 +[#2261]: https://github.com/trezor/trezor-firmware/pull/2261 +[#2284]: https://github.com/trezor/trezor-firmware/pull/2284 +[#2289]: https://github.com/trezor/trezor-firmware/pull/2289 +[#2297]: https://github.com/trezor/trezor-firmware/pull/2297 +[#2300]: https://github.com/trezor/trezor-firmware/pull/2300 +[#2313]: https://github.com/trezor/trezor-firmware/pull/2313 +[#2324]: https://github.com/trezor/trezor-firmware/pull/2324 +[#2341]: https://github.com/trezor/trezor-firmware/pull/2341 +[#2354]: https://github.com/trezor/trezor-firmware/pull/2354 +[#2355]: https://github.com/trezor/trezor-firmware/pull/2355 +[#2366]: https://github.com/trezor/trezor-firmware/pull/2366 +[#2380]: https://github.com/trezor/trezor-firmware/pull/2380 +[#2394]: https://github.com/trezor/trezor-firmware/pull/2394 +[#2398]: https://github.com/trezor/trezor-firmware/pull/2398 +[#2414]: https://github.com/trezor/trezor-firmware/pull/2414 +[#2415]: https://github.com/trezor/trezor-firmware/pull/2415 +[#2422]: https://github.com/trezor/trezor-firmware/pull/2422 +[#2427]: https://github.com/trezor/trezor-firmware/pull/2427 +[#2433]: https://github.com/trezor/trezor-firmware/pull/2433 +[#2442]: https://github.com/trezor/trezor-firmware/pull/2442 +[#2445]: https://github.com/trezor/trezor-firmware/pull/2445 +[#2453]: https://github.com/trezor/trezor-firmware/pull/2453 +[#2486]: https://github.com/trezor/trezor-firmware/pull/2486 +[#2487]: https://github.com/trezor/trezor-firmware/pull/2487 +[#2507]: https://github.com/trezor/trezor-firmware/pull/2507 +[#2525]: https://github.com/trezor/trezor-firmware/pull/2525 +[#2561]: https://github.com/trezor/trezor-firmware/pull/2561 +[#2570]: https://github.com/trezor/trezor-firmware/pull/2570 +[#2577]: https://github.com/trezor/trezor-firmware/pull/2577 +[#2587]: https://github.com/trezor/trezor-firmware/pull/2587 +[#2595]: https://github.com/trezor/trezor-firmware/pull/2595 +[#2610]: https://github.com/trezor/trezor-firmware/pull/2610 +[#2611]: https://github.com/trezor/trezor-firmware/pull/2611 +[#2623]: https://github.com/trezor/trezor-firmware/pull/2623 +[#2651]: https://github.com/trezor/trezor-firmware/pull/2651 +[#2682]: https://github.com/trezor/trezor-firmware/pull/2682 +[#2692]: https://github.com/trezor/trezor-firmware/pull/2692 +[#2746]: https://github.com/trezor/trezor-firmware/pull/2746 +[#2784]: https://github.com/trezor/trezor-firmware/pull/2784 +[#2818]: https://github.com/trezor/trezor-firmware/pull/2818 +[#2834]: https://github.com/trezor/trezor-firmware/pull/2834 +[#2841]: https://github.com/trezor/trezor-firmware/pull/2841 +[#2888]: https://github.com/trezor/trezor-firmware/pull/2888 +[#2899]: https://github.com/trezor/trezor-firmware/pull/2899 +[#2919]: https://github.com/trezor/trezor-firmware/pull/2919 +[#2937]: https://github.com/trezor/trezor-firmware/pull/2937 +[#2955]: https://github.com/trezor/trezor-firmware/pull/2955 +[#2989]: https://github.com/trezor/trezor-firmware/pull/2989 +[#3035]: https://github.com/trezor/trezor-firmware/pull/3035 +[#3047]: https://github.com/trezor/trezor-firmware/pull/3047 +[#3048]: https://github.com/trezor/trezor-firmware/pull/3048 +[#3205]: https://github.com/trezor/trezor-firmware/pull/3205 +[#3206]: https://github.com/trezor/trezor-firmware/pull/3206 +[#3208]: https://github.com/trezor/trezor-firmware/pull/3208 +[#3216]: https://github.com/trezor/trezor-firmware/pull/3216 +[#3218]: https://github.com/trezor/trezor-firmware/pull/3218 +[#3237]: https://github.com/trezor/trezor-firmware/pull/3237 +[#3242]: https://github.com/trezor/trezor-firmware/pull/3242 +[#3244]: https://github.com/trezor/trezor-firmware/pull/3244 +[#3246]: https://github.com/trezor/trezor-firmware/pull/3246 +[#3255]: https://github.com/trezor/trezor-firmware/pull/3255 +[#3256]: https://github.com/trezor/trezor-firmware/pull/3256 +[#3296]: https://github.com/trezor/trezor-firmware/pull/3296 +[#3311]: https://github.com/trezor/trezor-firmware/pull/3311 +[#3359]: https://github.com/trezor/trezor-firmware/pull/3359 +[#3370]: https://github.com/trezor/trezor-firmware/pull/3370 +[#3377]: https://github.com/trezor/trezor-firmware/pull/3377 +[#3411]: https://github.com/trezor/trezor-firmware/pull/3411 +[#3424]: https://github.com/trezor/trezor-firmware/pull/3424 +[#3434]: https://github.com/trezor/trezor-firmware/pull/3434 +[#3440]: https://github.com/trezor/trezor-firmware/pull/3440 +[#3442]: https://github.com/trezor/trezor-firmware/pull/3442 +[#3445]: https://github.com/trezor/trezor-firmware/pull/3445 +[#3458]: https://github.com/trezor/trezor-firmware/pull/3458 +[#3475]: https://github.com/trezor/trezor-firmware/pull/3475 +[#3477]: https://github.com/trezor/trezor-firmware/pull/3477 +[#3496]: https://github.com/trezor/trezor-firmware/pull/3496 +[#3517]: https://github.com/trezor/trezor-firmware/pull/3517 +[#3520]: https://github.com/trezor/trezor-firmware/pull/3520 +[#3539]: https://github.com/trezor/trezor-firmware/pull/3539 +[#3636]: https://github.com/trezor/trezor-firmware/pull/3636 +[#3640]: https://github.com/trezor/trezor-firmware/pull/3640 +[#3728]: https://github.com/trezor/trezor-firmware/pull/3728 +[#3855]: https://github.com/trezor/trezor-firmware/pull/3855 +[#3885]: https://github.com/trezor/trezor-firmware/pull/3885 +[#3895]: https://github.com/trezor/trezor-firmware/pull/3895 +[#3896]: https://github.com/trezor/trezor-firmware/pull/3896 +[#3907]: https://github.com/trezor/trezor-firmware/pull/3907 +[#3911]: https://github.com/trezor/trezor-firmware/pull/3911 +[#3916]: https://github.com/trezor/trezor-firmware/pull/3916 +[#3917]: https://github.com/trezor/trezor-firmware/pull/3917 +[#3919]: https://github.com/trezor/trezor-firmware/pull/3919 +[#3922]: https://github.com/trezor/trezor-firmware/pull/3922 +[#3925]: https://github.com/trezor/trezor-firmware/pull/3925 +[#3940]: https://github.com/trezor/trezor-firmware/pull/3940 +[#3965]: https://github.com/trezor/trezor-firmware/pull/3965 +[#3969]: https://github.com/trezor/trezor-firmware/pull/3969 +[#3972]: https://github.com/trezor/trezor-firmware/pull/3972 +[#3976]: https://github.com/trezor/trezor-firmware/pull/3976 +[#3987]: https://github.com/trezor/trezor-firmware/pull/3987 +[#3990]: https://github.com/trezor/trezor-firmware/pull/3990 +[#3992]: https://github.com/trezor/trezor-firmware/pull/3992 +[#4000]: https://github.com/trezor/trezor-firmware/pull/4000 +[#4006]: https://github.com/trezor/trezor-firmware/pull/4006 +[#4023]: https://github.com/trezor/trezor-firmware/pull/4023 +[#4030]: https://github.com/trezor/trezor-firmware/pull/4030 +[#4060]: https://github.com/trezor/trezor-firmware/pull/4060 +[#4063]: https://github.com/trezor/trezor-firmware/pull/4063 diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index a730f47cf3..95e194a70f 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -4,6 +4,81 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## [2.8.1] (21st August 2024) + +### Added +- [T3B1] Added support for T3B1. [#3728] +- [T3T1] Added PIN keyboard animation. [#3885] +- [T3T1] Added menu entry animation. [#3896] +- Improve precision of PIN timeout countdown. [#4000] +- [T3T1] New UI of confirming interaction-less firmware update. [#4030] + +### Changed +- [T3T1] Smoothened screen transitions by removing backlight fading. +- [T3T1] Improved resuming of interrupted animations. [#3987] +- [T3T1] Improve instruction screens during multi-share recovery process. [#3992] +- [T3T1] Improve share words swiping animation. [#4063] + +### Fixed +- [T2T1,T3T1] Added a progress indicator for the formatting operation. [#3035] +- [T3T1] Improved screen brightness settings. [#3969] +- [T3T1] Improve touch layer precision. [#3972] +- [T3T1] Fix More info screen during multi-share backup creation. [#4006] +- [T3T1] Fixed title sometimes not fitting into result screen. [#4023] +- [T3T1] Adjusted detection of swipes: vertical swipes are preferred over horizontal swipes. [#4060] +- Solana: added support for deprecated AToken Create `rent_sysvar` argument. [#3976] + +## [2.8.0] (9th July 2024) + +### Added +- [T3T1] Animated device label on homescreen/lockscreen. [#3895] +- [T3T1] Improved change homescreen flow. [#3907] +- [T3T1] Added word counter during wallet creation. [#3917] +- [T2B1,T3T1] Expose value of the Optiga SEC counter in `Features` message. + +### Changed +- Reworked PIN processing. + +### Removed +- CoSi functionality. [#3442] + +### Fixed +- [T3T1] Fixed swipe back from address QR code screen. [#3919] +- [T3T1] Fixed device authenticity check. [#3922] +- [T3T1] Improve swipe behavior and animations. [#3965] +- [T2B1,T3T1] Increase Optiga read timeout to avoid spurious RSODs. + + +## [2.7.2] (14th June 2024) + +### Fixed +- [T3T1] Fixed device authenticity check. [#3922] +- [T3T1] Wrong XPUB screen title. [#3911] +- [T2B1] Fixed device freeze after setup. [#3925] +- Translation fixes. [#3916] + + +## [2.7.1] (internal release) + +### Added +- [T2T1] Added user adjustable brightness setting. [#3208] +- Added basic support for STM32U5. [#3370] +- Cardano: Added support for tagged sets in CBOR (tag 258). [#3496] +- Cardano: Added support for Conway certificates. [#3496] +- Added ability to request Shamir backups with any number of groups/shares. [#3636] +- Added support for repeated backups. [#3640] +- [T2T1] Allow SD card hotswap based on production date. [#3940] +- Support extendable backup flag in SLIP-39. +- [T3T1] User interface implementation. + +### Changed +- Cardano: Increased max URL length to 128 bytes. [#3496] +- [T3T1] Upgrade to bootloader 2.1.6. [#3855] + +### Fixed +- Translate also texts for PIN progress loaders. [#3520] + + ## [2.7.0] (20th March 2024) ### Added @@ -840,10 +915,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#2937]: https://github.com/trezor/trezor-firmware/pull/2937 [#2955]: https://github.com/trezor/trezor-firmware/pull/2955 [#2989]: https://github.com/trezor/trezor-firmware/pull/2989 +[#3035]: https://github.com/trezor/trezor-firmware/pull/3035 [#3047]: https://github.com/trezor/trezor-firmware/pull/3047 [#3048]: https://github.com/trezor/trezor-firmware/pull/3048 [#3205]: https://github.com/trezor/trezor-firmware/pull/3205 [#3206]: https://github.com/trezor/trezor-firmware/pull/3206 +[#3208]: https://github.com/trezor/trezor-firmware/pull/3208 [#3216]: https://github.com/trezor/trezor-firmware/pull/3216 [#3218]: https://github.com/trezor/trezor-firmware/pull/3218 [#3237]: https://github.com/trezor/trezor-firmware/pull/3237 @@ -855,14 +932,45 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). [#3296]: https://github.com/trezor/trezor-firmware/pull/3296 [#3311]: https://github.com/trezor/trezor-firmware/pull/3311 [#3359]: https://github.com/trezor/trezor-firmware/pull/3359 +[#3370]: https://github.com/trezor/trezor-firmware/pull/3370 [#3377]: https://github.com/trezor/trezor-firmware/pull/3377 [#3411]: https://github.com/trezor/trezor-firmware/pull/3411 [#3424]: https://github.com/trezor/trezor-firmware/pull/3424 [#3434]: https://github.com/trezor/trezor-firmware/pull/3434 [#3440]: https://github.com/trezor/trezor-firmware/pull/3440 +[#3442]: https://github.com/trezor/trezor-firmware/pull/3442 [#3445]: https://github.com/trezor/trezor-firmware/pull/3445 [#3458]: https://github.com/trezor/trezor-firmware/pull/3458 [#3475]: https://github.com/trezor/trezor-firmware/pull/3475 [#3477]: https://github.com/trezor/trezor-firmware/pull/3477 +[#3496]: https://github.com/trezor/trezor-firmware/pull/3496 [#3517]: https://github.com/trezor/trezor-firmware/pull/3517 +[#3520]: https://github.com/trezor/trezor-firmware/pull/3520 [#3539]: https://github.com/trezor/trezor-firmware/pull/3539 +[#3636]: https://github.com/trezor/trezor-firmware/pull/3636 +[#3640]: https://github.com/trezor/trezor-firmware/pull/3640 +[#3728]: https://github.com/trezor/trezor-firmware/pull/3728 +[#3855]: https://github.com/trezor/trezor-firmware/pull/3855 +[#3885]: https://github.com/trezor/trezor-firmware/pull/3885 +[#3895]: https://github.com/trezor/trezor-firmware/pull/3895 +[#3896]: https://github.com/trezor/trezor-firmware/pull/3896 +[#3907]: https://github.com/trezor/trezor-firmware/pull/3907 +[#3911]: https://github.com/trezor/trezor-firmware/pull/3911 +[#3916]: https://github.com/trezor/trezor-firmware/pull/3916 +[#3917]: https://github.com/trezor/trezor-firmware/pull/3917 +[#3919]: https://github.com/trezor/trezor-firmware/pull/3919 +[#3922]: https://github.com/trezor/trezor-firmware/pull/3922 +[#3925]: https://github.com/trezor/trezor-firmware/pull/3925 +[#3940]: https://github.com/trezor/trezor-firmware/pull/3940 +[#3965]: https://github.com/trezor/trezor-firmware/pull/3965 +[#3969]: https://github.com/trezor/trezor-firmware/pull/3969 +[#3972]: https://github.com/trezor/trezor-firmware/pull/3972 +[#3976]: https://github.com/trezor/trezor-firmware/pull/3976 +[#3987]: https://github.com/trezor/trezor-firmware/pull/3987 +[#3992]: https://github.com/trezor/trezor-firmware/pull/3992 +[#4000]: https://github.com/trezor/trezor-firmware/pull/4000 +[#4006]: https://github.com/trezor/trezor-firmware/pull/4006 +[#4023]: https://github.com/trezor/trezor-firmware/pull/4023 +[#4030]: https://github.com/trezor/trezor-firmware/pull/4030 +[#4060]: https://github.com/trezor/trezor-firmware/pull/4060 +[#4063]: https://github.com/trezor/trezor-firmware/pull/4063 diff --git a/core/Makefile b/core/Makefile index 99125fbea4..25fbddc96b 100644 --- a/core/Makefile +++ b/core/Makefile @@ -1,3 +1,4 @@ + .PHONY: vendor # get the number of CPU cores in a "portable" manner @@ -36,71 +37,68 @@ ADDRESS_SANITIZER ?= 0 CMAKELISTS ?= 0 PYTEST_TIMEOUT ?= 500 TEST_LANG ?= "en" +THP ?= 0 # OpenOCD interface default. Alternative: ftdi/olimex-arm-usb-tiny-h OPENOCD_INTERFACE ?= stlink # OpenOCD transport default. Alternative: jtag OPENOCD_TRANSPORT ?= hla_swd -BINDGEN_MACROS_COMMON=-I../unix,-I../trezorhal/unix,-I../../build/unix,-I../../vendor/micropython/ports/unix,-I../../../crypto,-I../../../storage,-I../../vendor/micropython,-I../../vendor/micropython/lib/uzlib,-I../lib,-I../trezorhal,-I../trezorhal/unix,-I../models,-DTREZOR_EMULATOR,-DTREZOR_BOARD="boards/board-unix.h", - ifeq ($(TREZOR_MODEL), 1) MCU = STM32F2 -LAYOUT_FILE = embed/models/model_T1B1.h OPENOCD_TARGET = target/stm32f2x.cfg else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T)) MCU = STM32F4 -LAYOUT_FILE = embed/models/model_T2T1.h OPENOCD_TARGET = target/stm32f4x.cfg -BINDGEN_MACROS_MODEL = -DSTM32F427,-DTREZOR_MODEL_T,-DFLASH_BIT_ACCESS=1,-DFLASH_BLOCK_WORDS=1, MODEL_FEATURE = model_tt else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),R)) MCU = STM32F4 -LAYOUT_FILE = embed/models/model_T2B1.h OPENOCD_TARGET = target/stm32f4x.cfg -BINDGEN_MACROS_MODEL =-DSTM32F427,-DTREZOR_MODEL_R,-DFLASH_BIT_ACCESS=1,-DFLASH_BLOCK_WORDS=1, MODEL_FEATURE = model_tr else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T3T1)) MCU = STM32U5 OPENOCD_TARGET = target/stm32u5x.cfg -LAYOUT_FILE = embed/models/model_T3T1.h +MODEL_FEATURE = model_mercury +else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),T3B1)) +MCU = STM32U5 +OPENOCD_TARGET = target/stm32u5x.cfg +MODEL_FEATURE = model_tr else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),DISC1)) MCU = STM32F4 -LAYOUT_FILE = embed/models/model_D001.h +OPENOCD_TARGET = target/stm32f4x.cfg else ifeq ($(TREZOR_MODEL),$(filter $(TREZOR_MODEL),DISC2)) MCU = STM32U5 -LAYOUT_FILE = embed/models/model_D002.h OPENOCD_TARGET = target/stm32u5x.cfg else $(error Unknown TREZOR_MODEL: $(TREZOR_MODEL)) endif -FLASH_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FLASH_START) -BOARDLOADER_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOARDLOADER_START) -BOOTLOADER_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOOTLOADER_START) -FIRMWARE_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_START) -FIRMWARE_P2_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_P2_START) -STORAGE_1_OFFSET = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_1_OFFSET) -STORAGE_2_OFFSET = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_2_OFFSET) -STORAGE_SIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} NORCOW_SECTOR_SIZE) -BOARDLOADER_MAXSIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOARDLOADER_IMAGE_MAXSIZE) -BOOTLOADER_MAXSIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOOTLOADER_IMAGE_MAXSIZE) -FIRMWARE_MAXSIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_IMAGE_MAXSIZE) -FIRMWARE_P1_MAXSIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_P1_IMAGE_MAXSIZE) -FIRMWARE_P2_MAXSIZE = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_P2_IMAGE_MAXSIZE) -BOARDLOADER_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOARDLOADER_SECTOR_START) -BOARDLOADER_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOARDLOADER_SECTOR_END) -BOOTLOADER_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOOTLOADER_SECTOR_START) -BOOTLOADER_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} BOOTLOADER_SECTOR_END) -FIRMWARE_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_SECTOR_START) -FIRMWARE_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_SECTOR_END) -FIRMWARE_P2_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_P2_SECTOR_START) -FIRMWARE_P2_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} FIRMWARE_P2_SECTOR_END) -STORAGE_1_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_1_SECTOR_START) -STORAGE_1_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_1_SECTOR_END) -STORAGE_2_SECTOR_START = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_2_SECTOR_START) -STORAGE_2_SECTOR_END = $(shell python ./tools/layout_parser.py ${LAYOUT_FILE} STORAGE_2_SECTOR_END) +FLASH_START = $(shell layout_parser ${TREZOR_MODEL} FLASH_START) +BOARDLOADER_START = $(shell layout_parser ${TREZOR_MODEL} BOARDLOADER_START) +BOOTLOADER_START = $(shell layout_parser ${TREZOR_MODEL} BOOTLOADER_START) +FIRMWARE_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_START) +FIRMWARE_P2_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P2_START) +STORAGE_1_OFFSET = $(shell layout_parser ${TREZOR_MODEL} STORAGE_1_OFFSET) +STORAGE_2_OFFSET = $(shell layout_parser ${TREZOR_MODEL} STORAGE_2_OFFSET) +STORAGE_SIZE = $(shell layout_parser ${TREZOR_MODEL} NORCOW_SECTOR_SIZE) +BOARDLOADER_MAXSIZE = $(shell layout_parser ${TREZOR_MODEL} BOARDLOADER_IMAGE_MAXSIZE) +BOOTLOADER_MAXSIZE = $(shell layout_parser ${TREZOR_MODEL} BOOTLOADER_IMAGE_MAXSIZE) +FIRMWARE_MAXSIZE = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_IMAGE_MAXSIZE) +FIRMWARE_P1_MAXSIZE = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P1_IMAGE_MAXSIZE) +FIRMWARE_P2_MAXSIZE = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P2_IMAGE_MAXSIZE) +BOARDLOADER_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} BOARDLOADER_SECTOR_START) +BOARDLOADER_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} BOARDLOADER_SECTOR_END) +BOOTLOADER_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} BOOTLOADER_SECTOR_START) +BOOTLOADER_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} BOOTLOADER_SECTOR_END) +FIRMWARE_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_SECTOR_START) +FIRMWARE_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_SECTOR_END) +FIRMWARE_P2_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P2_SECTOR_START) +FIRMWARE_P2_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} FIRMWARE_P2_SECTOR_END) +STORAGE_1_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} STORAGE_1_SECTOR_START) +STORAGE_1_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} STORAGE_1_SECTOR_END) +STORAGE_2_SECTOR_START = $(shell layout_parser ${TREZOR_MODEL} STORAGE_2_SECTOR_START) +STORAGE_2_SECTOR_END = $(shell layout_parser ${TREZOR_MODEL} STORAGE_2_SECTOR_END) OPENOCD = openocd -f interface/$(OPENOCD_INTERFACE).cfg -c "transport select $(OPENOCD_TRANSPORT)" -f $(OPENOCD_TARGET) @@ -143,7 +141,6 @@ emu: ## run emulator test: ## run unit tests cd tests ; ./run_tests.sh $(TESTOPTS) -test_rust: export BINDGEN_MACROS=$(BINDGEN_MACROS_COMMON)$(BINDGEN_MACROS_MODEL) test_rust: ## run rs unit tests cd embed/rust ; cargo test $(TESTOPTS) --target=$(RUST_TARGET) \ --no-default-features --features $(MODEL_FEATURE),test \ @@ -213,7 +210,6 @@ typecheck: pyright pyright: python ../tools/pyright_tool.py -clippy: export BINDGEN_MACROS:=$(BINDGEN_MACROS_COMMON)$(BINDGEN_MACROS_MODEL) clippy: cd embed/rust ; cargo clippy $(TESTOPTS) --all-features --target=$(RUST_TARGET) @@ -241,18 +237,25 @@ build_embed: build_boardloader build_bootloader build_firmware # build boardload build_boardloader: ## build boardloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOARDLOADER_BUILD_DIR)/boardloader.bin build_bootloader: ## build bootloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin + CMAKELISTS="$(CMAKELISTS)" BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \ + NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_BUILD_DIR)/bootloader.bin build_bootloader_ci: ## build CI device testing bootloader $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_CI_BUILD_DIR)/bootloader.bin build_bootloader_emu: ## build the unix bootloader emulator - $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf + $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf + +build_bootloader_emu_debug: ## build the unix bootloader emulator + $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" TREZOR_EMULATOR_DEBUGGABLE=1 \ + $(BOOTLOADER_EMU_BUILD_DIR)/bootloader.elf build_prodtest: ## build production test firmware $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ @@ -260,7 +263,7 @@ build_prodtest: ## build production test firmware build_reflash: ## build reflash firmware + reflash image $(SCONS) CFLAGS="$(CFLAGS)" PRODUCTION="$(PRODUCTION)" TREZOR_MODEL="$(TREZOR_MODEL)" \ - CMAKELISTS="$(CMAKELISTS)" $(REFLASH_BUILD_DIR)/reflash.bin + CMAKELISTS="$(CMAKELISTS)" NEW_RENDERING="$(NEW_RENDERING)" $(REFLASH_BUILD_DIR)/reflash.bin dd if=build/boardloader/boardloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=0 dd if=build/bootloader/bootloader.bin of=$(REFLASH_BUILD_DIR)/sdimage.bin bs=1 seek=49152 @@ -269,24 +272,26 @@ build_firmware: templates build_cross ## build firmware with frozen modules TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" \ BOOTLOADER_QA="$(BOOTLOADER_QA)" BOOTLOADER_DEVEL="$(BOOTLOADER_DEVEL)" \ - DISABLE_OPTIGA="$(DISABLE_OPTIGA)" \ + DISABLE_OPTIGA="$(DISABLE_OPTIGA)" THP="$(THP)" NEW_RENDERING="$(NEW_RENDERING)" \ $(FIRMWARE_BUILD_DIR)/firmware.bin build_unix: templates ## build unix port $(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ - TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ - PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" + TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" THP="$(THP)" \ + PYOPT="0" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \ + NEW_RENDERING="$(NEW_RENDERING)" build_unix_frozen: templates build_cross ## build unix port with frozen modules $(SCONS) CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ PYOPT="$(PYOPT)" BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN="$(ADDRESS_SANITIZER)" \ - TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1 + TREZOR_MEMPERF="$(TREZOR_MEMPERF)" TREZOR_EMULATOR_FROZEN=1 NEW_RENDERING="$(NEW_RENDERING)" build_unix_debug: templates ## build unix port $(SCONS) --max-drift=1 CFLAGS="$(CFLAGS)" $(UNIX_BUILD_DIR)/trezor-emu-core $(UNIX_PORT_OPTS) \ TREZOR_MODEL="$(TREZOR_MODEL)" CMAKELISTS="$(CMAKELISTS)" \ - BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 + BITCOIN_ONLY="$(BITCOIN_ONLY)" TREZOR_EMULATOR_ASAN=1 TREZOR_EMULATOR_DEBUGGABLE=1 \ + NEW_RENDERING="$(NEW_RENDERING)" build_cross: ## build mpy-cross port $(MAKE) -C vendor/micropython/mpy-cross $(CROSS_PORT_OPTS) @@ -427,8 +432,8 @@ sizecheck: ## check sizes of binary files test $(FIRMWARE_MAXSIZE) -ge $(shell wc -c < $(FIRMWARE_BUILD_DIR)/firmware.bin) combine: ## combine boardloader + bootloader + prodtest into one combined image - ./tools/combine_firmware \ - $(LAYOUT_FILE) \ + combine_firmware \ + $(TREZOR_MODEL) \ $(PRODTEST_BUILD_DIR)/combined.bin \ -b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \ -b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \ @@ -436,8 +441,8 @@ combine: ## combine boardloader + bootloader + prodtest into one combined image ifeq ($(MCU),$(filter $(MCU),STM32F4)) combine_fw: ## combine boardloader + bootloader + firmware into one combined image - ./tools/combine_firmware \ - $(LAYOUT_FILE) \ + combine_firmware \ + $(TREZOR_MODEL) \ $(PRODTEST_BUILD_DIR)/combined.bin \ -b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \ -b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \ @@ -445,8 +450,8 @@ combine_fw: ## combine boardloader + bootloader + firmware into one combined ima -b FIRMWARE_P2 $(FIRMWARE_BUILD_DIR)/firmware.bin.p2 else ifeq ($(MCU),$(filter $(MCU),STM32U5)) combine_fw: ## combine boardloader + bootloader + firmware into one combined image - ./tools/combine_firmware \ - $(LAYOUT_FILE) \ + combine_firmware \ + $(TREZOR_MODEL) \ $(PRODTEST_BUILD_DIR)/combined.bin \ -b BOARDLOADER $(BOARDLOADER_BUILD_DIR)/boardloader.bin \ -b BOOTLOADER $(BOOTLOADER_BUILD_DIR)/bootloader.bin \ diff --git a/core/SConscript.boardloader b/core/SConscript.boardloader index 03a7b731b1..cc31e0b6b8 100644 --- a/core/SConscript.boardloader +++ b/core/SConscript.boardloader @@ -1,10 +1,12 @@ # pylint: disable=E0602 import os -import tools +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' if TREZOR_MODEL in ('1', ): # skip boardloader build @@ -20,10 +22,14 @@ if TREZOR_MODEL in ('1', ): FEATURES_WANTED = ["sd_card"] +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") + CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = ["BOARDLOADER"] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] @@ -41,6 +47,9 @@ CPPDEFINES_MOD += [ 'ED25519_NO_PRECOMP', ] SOURCE_MOD += [ + 'vendor/trezor-storage/flash_area.c', +] +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/blake2s.c', 'vendor/trezor-crypto/ed25519-donna/curve25519-donna-32bit.c', 'vendor/trezor-crypto/ed25519-donna/curve25519-donna-helpers.c', @@ -50,7 +59,6 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/ed25519-donna/modm-donna-32bit.c', 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/sha2.c', - 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -60,13 +68,28 @@ CPPPATH_MOD += [ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', + 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', ] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gfx_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + env = Environment(ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), @@ -74,7 +97,7 @@ env = Environment(ENV=os.environ, CPPDEFINES_IMPLICIT=[] ) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] @@ -130,7 +153,7 @@ env.Replace( ) env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_BOARDLOADER + SOURCE_HAL, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_BOARDLOADER + SOURCE_HAL, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( @@ -145,6 +168,7 @@ cmake_gen = env.Command( obj_program = [] obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero') obj_program += env.Object(source=SOURCE_BOARDLOADER) obj_program += env.Object(source=SOURCE_HAL) @@ -155,7 +179,7 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) -BINARY_NAME = f"build/boardloader/boardloader-{tools.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/boardloader/boardloader-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/boardloader/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() BINARY_NAME += "-dirty" if tools.get_git_modified() else "" diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 00529e0eb1..e5226cd313 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -1,12 +1,14 @@ # pylint: disable=E0602 import os -import tools +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) BOOTLOADER_QA = ARGUMENTS.get('BOOTLOADER_QA', '0') == '1' PRODUCTION = 0 if BOOTLOADER_QA else ARGUMENTS.get('PRODUCTION', '0') == '1' +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) if TREZOR_MODEL in ('1', ): # skip bootloader build @@ -22,32 +24,45 @@ if TREZOR_MODEL in ('1', ): FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d"] +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") + CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('R', ): +if TREZOR_MODEL in ('R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_PixelOperator_Regular_8' FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperator_Regular_8' - FONT_BIG=None + FONT_BIG='Font_PixelOperator_Regular_8' + FONT_NORMAL_UPPER='Font_PixelOperator_Regular_8_upper' + FONT_BOLD_UPPER=None + FONT_SUB=None elif TREZOR_MODEL in ('T', 'DISC1', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD='Font_TTHoves_Regular_21' - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD='Font_TTHoves_Bold_17_upper' FONT_MONO='Font_TTHoves_Regular_21' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None elif TREZOR_MODEL in ('T3T1',): FONT_NORMAL='Font_TTSatoshi_DemiBold_21' FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21' - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD='Font_TTHoves_Bold_17_upper' FONT_MONO='Font_TTSatoshi_DemiBold_21' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None # modtrezorcrypto CCFLAGS_MOD += '-Wno-sequence-point ' @@ -65,6 +80,9 @@ CPPDEFINES_MOD += [ ] SOURCE_MOD += [ + 'vendor/trezor-storage/flash_area.c', +] +SOURCE_MOD_CRYPTO = [ 'vendor/trezor-crypto/blake2s.c', 'vendor/trezor-crypto/chacha_drbg.c', 'vendor/trezor-crypto/chacha20poly1305/chacha_merged.c', @@ -77,7 +95,6 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', - 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -90,9 +107,13 @@ SOURCE_MOD += [ 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_mono8.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', @@ -102,6 +123,17 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gfx_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + SOURCE_NANOPB = [ 'vendor/nanopb/pb_common.c', 'vendor/nanopb/pb_decode.c', @@ -114,6 +146,9 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment( ENV=os.environ, @@ -121,7 +156,7 @@ env = Environment( CPPDEFINES_IMPLICIT=[] ) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] @@ -133,6 +168,7 @@ SOURCE_BOOTLOADER = [ 'embed/bootloader/main.c', 'embed/bootloader/messages.c', 'embed/bootloader/protob/messages.pb.c', + 'embed/bootloader/version_check.c', ] @@ -189,11 +225,11 @@ env.Replace( ) env.Replace( - HEADERTOOL='tools/headertool.py', + HEADERTOOL='headertool', ) env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'] + [f"PRODUCTION={int(PRODUCTION)}", f"BOOTLOADER_QA={int(BOOTLOADER_QA)}"])) cmake_gen = env.Command( @@ -220,16 +256,23 @@ def cargo_build(): profile = '' if TREZOR_MODEL in ("1",): features = ["model_t1"] - elif TREZOR_MODEL in ("R",): + elif TREZOR_MODEL in ("R", "T3B1"): features = ["model_tr"] elif TREZOR_MODEL in ("T3T1",): features = ["model_mercury"] else: features = ["model_tt"] + + if TREZOR_MODEL in ("R",): + features.append("ui_empty_lock") + features.append("ui") features.append("bootloader") features.extend(FEATURES_AVAILABLE) + if NEW_RENDERING: + features.append('new_rendering') + cargo_opts = [ f'--target={env.get("ENV")["RUST_TARGET"]}', f'--target-dir=../../build/bootloader/rust', @@ -257,6 +300,7 @@ env.Append(LINKFLAGS=f' -l{RUST_LIB}') obj_program = [] obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero') obj_program += env.Object(source=SOURCE_BOOTLOADER) obj_program += env.Object(source=SOURCE_NANOPB) obj_program += env.Object(source=SOURCE_HAL) @@ -273,7 +317,7 @@ env.Depends(program_elf, rust) SUFFIX = '_qa' if BOOTLOADER_QA else '' -BINARY_NAME = f"build/bootloader/bootloader-{tools.get_model_identifier(TREZOR_MODEL)}{SUFFIX}" +BINARY_NAME = f"build/bootloader/bootloader-{models.get_model_identifier(TREZOR_MODEL)}{SUFFIX}" BINARY_NAME += "-" + tools.get_version('embed/bootloader/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() BINARY_NAME += "-dirty" if tools.get_git_modified() else "" diff --git a/core/SConscript.bootloader_ci b/core/SConscript.bootloader_ci index 1835b93055..73e7a688c7 100644 --- a/core/SConscript.bootloader_ci +++ b/core/SConscript.bootloader_ci @@ -1,10 +1,12 @@ # pylint: disable=E0602 import os -import tools +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) if TREZOR_MODEL in ('1', 'DISC1', 'DISC2'): # skip bootloader_ci build @@ -24,28 +26,38 @@ CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD=None FONT_BOLD=None FONT_MONO='Font_PixelOperatorMono_Regular_8' - FONT_BIG=None + FONT_BIG='Font_PixelOperator_Regular_8' + FONT_NORMAL_UPPER='Font_PixelOperator_Regular_8_upper' + FONT_BOLD_UPPER=None + FONT_SUB=None elif TREZOR_MODEL in ('T',): FONT_NORMAL='Font_Roboto_Regular_20' FONT_DEMIBOLD=None FONT_BOLD=None FONT_MONO='Font_RobotoMono_Medium_20' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None elif TREZOR_MODEL in ('T3T1',): FONT_NORMAL='Font_TTSatoshi_DemiBold_21' FONT_DEMIBOLD=None FONT_BOLD=None FONT_MONO='Font_RobotoMono_Medium_21' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None # modtrezorcrypto CCFLAGS_MOD += '-Wno-sequence-point ' @@ -60,6 +72,9 @@ CPPDEFINES_MOD += [ 'ED25519_NO_PRECOMP', ] SOURCE_MOD += [ + 'vendor/trezor-storage/flash_area.c', +] +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/blake2s.c', 'vendor/trezor-crypto/chacha_drbg.c', 'vendor/trezor-crypto/chacha20poly1305/chacha_merged.c', @@ -72,7 +87,6 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/memzero.c', 'vendor/trezor-crypto/rand.c', 'vendor/trezor-crypto/sha2.c', - 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -82,8 +96,9 @@ CPPPATH_MOD += [ SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/rand.c', 'embed/lib/colors.c', + 'embed/lib/display_draw.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/image.c', @@ -106,13 +121,16 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment( ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CPPDEFINES_IMPLICIT=[] ) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] @@ -173,14 +191,14 @@ env.Replace( ] + CPPDEFINES_MOD + CPPDEFINES_HAL, ASFLAGS=env.get('ENV')['CPU_ASFLAGS'], ASPPFLAGS='$CFLAGS $CCFLAGS', - ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_HAL+ SOURCE_NANOPB, ) + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_BOOTLOADER + SOURCE_HAL+ SOURCE_NANOPB, ) env.Replace( - HEADERTOOL='tools/headertool.py', + HEADERTOOL='headertool', ) env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_HAL, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( @@ -196,6 +214,7 @@ cmake_gen = env.Command( obj_program = [] obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero') obj_program += env.Object(source=SOURCE_BOOTLOADER) obj_program += env.Object(source=SOURCE_NANOPB) obj_program += env.Object(source=SOURCE_HAL) @@ -207,7 +226,7 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) -BINARY_NAME = f"build/bootloader_ci/bootloader_ci-{tools.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/bootloader_ci/bootloader_ci-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/bootloader_ci/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() BINARY_NAME += "-dirty" if tools.get_git_modified() else "" diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 22bbc26de0..9d0627cbcc 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -1,14 +1,14 @@ # pylint: disable=E0602 import os -import tools -import boards +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) -DMA2D = False +HW_REVISION = 'emulator' +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) -if TREZOR_MODEL in ('1', 'DISC1'): +if TREZOR_MODEL in ('1', 'DISC1', 'DISC2'): # skip bootloader build env = Environment() def build_bootloader(target,source,env): @@ -20,31 +20,46 @@ if TREZOR_MODEL in ('1', 'DISC1'): ) Return() -FEATURES_WANTED = ["input", "rgb_led", "dma2d"] +FEATURES_WANTED = ["input", "rgb_led", "dma2d", "optiga_hal"] + +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") CCFLAGS_MOD = '' CPPPATH_MOD = [] +CPPDEFINES_HAL = [] +PATH_HAL = [] CPPDEFINES_MOD = [] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_PixelOperator_Regular_8' FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperator_Regular_8' - FONT_BIG=None + FONT_BIG='Font_PixelOperator_Regular_8' + FONT_NORMAL_UPPER='Font_PixelOperator_Regular_8_upper' + FONT_BOLD_UPPER=None + FONT_SUB=None elif TREZOR_MODEL in ('T', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD=None - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD=None FONT_MONO=None FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None elif TREZOR_MODEL in ('T3T1',): FONT_NORMAL='Font_TTSatoshi_DemiBold_21' FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21' - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD=None FONT_MONO='Font_TTSatoshi_DemiBold_21' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None # modtrezorcrypto CCFLAGS_MOD += '-Wno-sequence-point ' @@ -60,7 +75,7 @@ CPPDEFINES_MOD += [ 'TREZOR_UI2', 'FANCY_FATAL_ERROR' ] -SOURCE_MOD += [ +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/blake2s.c', 'vendor/trezor-crypto/chacha_drbg.c', 'vendor/trezor-crypto/chacha20poly1305/chacha_merged.c', @@ -87,13 +102,16 @@ SOURCE_MOD += [ 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', - 'embed/lib/dma2d_emul.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_mono8.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', 'embed/lib/image.c', + 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', - 'embed/lib/touch.c', 'embed/lib/unit_variant.c', 'vendor/micropython/lib/uzlib/adler32.c', 'vendor/micropython/lib/uzlib/crc32.c', @@ -101,23 +119,15 @@ SOURCE_MOD += [ 'vendor/trezor-storage/flash_area.c', ] -if TREZOR_MODEL in ('1', ): - SOURCE_MOD += [ - 'embed/models/model_T1B1_layout.c', - ] -elif TREZOR_MODEL in ('T', ): - SOURCE_MOD += [ - 'embed/models/model_T2T1_layout.c', - ] -elif TREZOR_MODEL in ('R', ): +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] SOURCE_MOD += [ - 'embed/models/model_T2B1_layout.c', + 'embed/lib/gfx_draw.c', ] -elif TREZOR_MODEL in ('T3T1',): +else: SOURCE_MOD += [ - 'embed/models/model_T3T1_layout.c', - ] - + 'embed/lib/display_draw.c', +] SOURCE_NANOPB = [ 'vendor/nanopb/pb_common.c', @@ -130,26 +140,31 @@ SOURCE_BOOTLOADER = [ 'embed/bootloader/main.c', 'embed/bootloader/messages.c', 'embed/bootloader/emulator.c', + 'embed/bootloader/version_check.c', 'embed/bootloader/protob/messages.pb.c', ] SOURCE_TREZORHAL = [ 'embed/trezorhal/unix/boot_args.c', - 'embed/trezorhal/unix/display-unix.c', + 'embed/trezorhal/unix/common.c', 'embed/trezorhal/unix/fault_handlers.c', 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/flash_otp.c', - 'embed/trezorhal/unix/common.c', - 'embed/trezorhal/unix/touch/touch.c', - 'embed/trezorhal/unix/rng.c', - 'embed/trezorhal/unix/usb.c', + 'embed/trezorhal/unix/monoctr.c', 'embed/trezorhal/unix/random_delays.c', + 'embed/trezorhal/unix/rng.c', 'embed/trezorhal/unix/secret.c', + 'embed/trezorhal/unix/usb.c', ] -if TREZOR_MODEL in ('R', 'T3T1'): +if NEW_RENDERING: + SOURCE_TREZORHAL += [ + 'embed/trezorhal/unix/display_driver.c', + 'embed/trezorhal/xdisplay_legacy.c', + ] +else: SOURCE_TREZORHAL += [ - 'embed/trezorhal/unix/optiga_hal.c', + 'embed/trezorhal/unix/display-unix.c', ] SOURCE_UNIX = [ @@ -164,9 +179,14 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment(ENV=os.environ, CFLAGS='%s -DCONFIDENTIAL= -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0'))) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_UNIX, PATH_HAL) + env.Replace( CP='cp', AS='as', @@ -179,24 +199,8 @@ env.Replace( PYTHON='python', MAKECMAKELISTS='$PYTHON tools/make_cmakelists.py', ) -env.Replace( - TREZOR_MODEL=TREZOR_MODEL, ) - -if TREZOR_MODEL in ('T', 'R'): - CPU_MODEL = 'STM32F427xx' -elif TREZOR_MODEL in ('T3T1', ): - CPU_MODEL = 'STM32U585xx' -elif TREZOR_MODEL in ('DISC1', ): - CPU_MODEL = 'STM32F429xx' -elif TREZOR_MODEL in ('DISC2', ): - CPU_MODEL = 'STM32U5A9xx' -elif TREZOR_MODEL in ('1',): - CPU_MODEL = 'STM32F405xx' -else: - raise ValueError('Unknown Trezor model') - -MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) -MODEL_AS_NUMBER = str(boards.get_hw_model_as_number(MODEL_IDENTIFIER)) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) +MODEL_AS_NUMBER = str(models.get_hw_model_as_number(MODEL_IDENTIFIER)) ALLPATHS = ['embed/rust', 'embed/bootloader', @@ -209,7 +213,7 @@ ALLPATHS = ['embed/rust', 'embed/unix', 'embed/extmod/modtrezorui', 'vendor/nanopb', - ] + CPPPATH_MOD + ] + CPPPATH_MOD + PATH_HAL env.Replace( COPT=env.get('ENV').get('OPTIMIZE', '-Os'), @@ -225,18 +229,11 @@ env.Replace( CPPDEFINES=[ 'BOOTLOADER', 'TREZOR_EMULATOR', - CPU_MODEL, - 'HW_MODEL=' + MODEL_AS_NUMBER, - 'HW_REVISION=' + ('10' if TREZOR_MODEL in ('R',) else '0'), 'TREZOR_MODEL_'+TREZOR_MODEL, - 'TREZOR_BOARD=\\"boards/board-unix.h\\"', - ('FLASH_BIT_ACCESS', '1'), - ('FLASH_BLOCK_WORDS', '1'), - 'MCU_TYPE='+CPU_MODEL, 'PB_FIELD_16BIT', 'PB_ENCODE_ARRAYS_UNPACKED', 'PB_VALIDATE_UTF8', - ] + CPPDEFINES_MOD, + ] + CPPDEFINES_MOD + CPPDEFINES_HAL, ASPPFLAGS='$CFLAGS $CCFLAGS', ) try: @@ -246,7 +243,7 @@ except OSError: env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_TREZORHAL + SOURCE_UNIX, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_BOOTLOADER + SOURCE_NANOPB + SOURCE_TREZORHAL + SOURCE_UNIX, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'])) cmake_gen = env.Command( @@ -260,36 +257,37 @@ cmake_gen = env.Command( # Rust library # -RUST_TARGET = 'x86_64-unknown-linux-gnu' -RUST_PROFILE = 'release' +RUST_TARGET = os.popen("rustc -vV | sed -n 's/host: //p'").read().strip() RUST_LIB = 'trezor_lib' -RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/{RUST_PROFILE}' + +if ARGUMENTS.get('TREZOR_EMULATOR_DEBUGGABLE', '0') == '1': + RUST_PROFILE = 'dev' + RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/debug' +else: + RUST_PROFILE = 'release' + RUST_LIBDIR = f'build/bootloader_emu/rust/{RUST_TARGET}/release' + RUST_LIBPATH = f'{RUST_LIBDIR}/lib{RUST_LIB}.a' def cargo_build(): - # Determine the profile build flags. - if RUST_PROFILE == 'release': - profile = '--release' - else: - profile = '' if TREZOR_MODEL in ("1",): features = ["model_t1"] - elif TREZOR_MODEL in ("R",): + elif TREZOR_MODEL in ("R", "T3B1"): features = ["model_tr"] elif TREZOR_MODEL in ("T3T1",): features = ["model_mercury"] else: features = ["model_tt"] - if TREZOR_MODEL in ('T', 'T3T1'): - features.append('touch') - features.append('backlight') - features.append('dma2d') - if TREZOR_MODEL in ('R', '1'): - features.append('button') + if TREZOR_MODEL in ("R",): + features.append("ui_empty_lock") + + if NEW_RENDERING: + features.append('new_rendering') features.append("ui") features.append("bootloader") + features.extend(FEATURES_AVAILABLE) cargo_opts = [ @@ -303,7 +301,7 @@ def cargo_build(): bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) - return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build {profile} ' + ' '.join(cargo_opts) + return f'export BINDGEN_MACROS=\'{bindgen_macros}\'; cd embed/rust; cargo build --profile {RUST_PROFILE} ' + ' '.join(cargo_opts) rust = env.Command( target=RUST_LIBPATH, @@ -320,6 +318,7 @@ env.Append(LINKFLAGS='-lm') obj_program = [] obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero') obj_program += env.Object(source=SOURCE_BOOTLOADER) obj_program += env.Object(source=SOURCE_NANOPB) obj_program += env.Object(source=SOURCE_TREZORHAL) diff --git a/core/SConscript.firmware b/core/SConscript.firmware index 1f926fcba5..5e199f2617 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -2,7 +2,7 @@ # fmt: off import os -import tools +import tools, models BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0') PRODUCTION = ARGUMENTS.get('PRODUCTION', '0') == '1' @@ -13,6 +13,9 @@ TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) PYOPT = ARGUMENTS.get('PYOPT', '1') DISABLE_OPTIGA = ARGUMENTS.get('DISABLE_OPTIGA', '0') == '1' +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) FEATURE_FLAGS = { @@ -25,29 +28,47 @@ FEATURE_FLAGS = { FEATURES_WANTED = ["input", "sbu", "sd_card", "rgb_led", "dma2d", "consumption_mask", "usb" ,"optiga", "haptic"] if DISABLE_OPTIGA and PYOPT == '0': FEATURES_WANTED.remove("optiga") +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] FROZEN = True -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_Unifont_Bold_16' FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperatorMono_Regular_8' FONT_BIG='Font_Unifont_Regular_16' -elif TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): + FONT_NORMAL_UPPER='Font_PixelOperator_Regular_8_upper' + FONT_BOLD_UPPER='Font_PixelOperator_Bold_8_upper' + FONT_SUB=None +elif TREZOR_MODEL in ('T', 'DISC1', 'DISC2'): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD='Font_TTHoves_DemiBold_21' - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD=None FONT_MONO='Font_RobotoMono_Medium_20' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None +elif TREZOR_MODEL in ('T3T1',): + FONT_NORMAL='Font_TTSatoshi_DemiBold_21' + FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21' + FONT_BOLD='Font_TTSatoshi_DemiBold_21' + FONT_MONO='Font_RobotoMono_Medium_21' + FONT_BIG='Font_TTSatoshi_DemiBold_42' + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB='Font_TTSatoshi_DemiBold_18' # modtrezorconfig CPPPATH_MOD += [ @@ -83,6 +104,8 @@ SOURCE_MOD += [ 'embed/extmod/modtrezorcrypto/crc.c', 'embed/extmod/modtrezorcrypto/modtrezorcrypto.c', 'embed/extmod/modtrezorcrypto/rand.c', +] +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/address.c', 'vendor/trezor-crypto/aes/aes_modes.c', 'vendor/trezor-crypto/aes/aesccm.c', @@ -138,7 +161,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/tls_prf.c', ] if EVERYTHING: - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/cardano.c', 'vendor/trezor-crypto/monero/base58.c', 'vendor/trezor-crypto/monero/serialize.c', @@ -160,11 +183,12 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: 'USE_EXTERNAL_ASM', 'USE_EXTERNAL_DEFAULT_CALLBACKS', ('ECMULT_GEN_PREC_BITS', '2'), - ('ECMULT_WINDOW_SIZE', '8'), + ('ECMULT_WINDOW_SIZE', '2'), 'ENABLE_MODULE_GENERATOR', 'ENABLE_MODULE_RECOVERY', 'ENABLE_MODULE_SCHNORRSIG', 'ENABLE_MODULE_EXTRAKEYS', + 'ENABLE_MODULE_ECDH', ] SOURCE_MOD_SECP256K1_ZKP = [ 'vendor/secp256k1-zkp/src/secp256k1.c', @@ -172,7 +196,7 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: 'vendor/secp256k1-zkp/src/precomputed_ecmult_gen.c', 'vendor/secp256k1-zkp/src/asm/field_10x26_arm.s' ] - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/zkp_context.c', 'vendor/trezor-crypto/zkp_ecdsa.c', 'vendor/trezor-crypto/zkp_bip340.c', @@ -184,7 +208,7 @@ if FEATURE_FLAGS["AES_GCM"]: 'USE_AES_GCM', 'AES_VAR', ] - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/aes/gf128mul.c', 'vendor/trezor-crypto/aes/aesgcm.c', ] @@ -203,9 +227,13 @@ SOURCE_MOD += [ 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', + 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', @@ -216,6 +244,17 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gfx_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + CPPDEFINES_MOD += [ 'TREZOR_UI2', 'TRANSLATIONS', @@ -384,6 +423,11 @@ TRANSLATION_DATA = [ "translations/order.json", ] +if THP: + CPPDEFINES_MOD += ['USE_THP'] + SOURCE_MOD += [ + 'vendor/trezor-crypto/elligator2.c', + ] # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) @@ -391,6 +435,9 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED @@ -400,7 +447,7 @@ env = Environment( CPPDEFINES_IMPLICIT=[] ) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] @@ -415,12 +462,15 @@ SOURCE_FIRMWARE = [ ] -if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): +if TREZOR_MODEL in ('T', 'DISC1', 'DISC2'): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' -elif TREZOR_MODEL in ('1', 'R'): +elif TREZOR_MODEL in ('1', 'R', 'T3B1'): UI_LAYOUT = 'UI_LAYOUT_TR' ui_layout_feature = 'model_tr' +elif TREZOR_MODEL in ('T3T1',): + UI_LAYOUT = 'UI_LAYOUT_MERCURY' + ui_layout_feature = 'model_mercury' else: raise ValueError('Unknown Trezor model') @@ -488,7 +538,7 @@ env.Replace( ) env.Replace( - HEADERTOOL='tools/headertool.py', + HEADERTOOL='headertool', PYTHON='python', MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py', MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py', @@ -595,6 +645,12 @@ if FROZEN: SOURCE_PY_DIR + 'trezor/ui/layouts/tr/fido.py', ] if not EVERYTHING else [] )) + elif UI_LAYOUT == 'UI_LAYOUT_MERCURY': + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/ui/layouts/mercury/*.py', + exclude=[ + SOURCE_PY_DIR + 'trezor/ui/layouts/mercury/fido.py', + ] if not EVERYTHING else [] + )) else: raise ValueError('Unknown layout') @@ -706,6 +762,7 @@ if FROZEN: backlight='backlight' in FEATURES_AVAILABLE, optiga='optiga' in FEATURES_AVAILABLE, ui_layout=UI_LAYOUT, + thp=THP, ) source_mpyc = env.FrozenCFile( @@ -718,9 +775,10 @@ if FROZEN: # Program objects # -source_files = SOURCE_MOD + SOURCE_FIRMWARE + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED + SOURCE_HAL +source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_FIRMWARE + SOURCE_MICROPYTHON + SOURCE_MICROPYTHON_SPEED + SOURCE_HAL obj_program = [] obj_program.extend(env.Object(source=SOURCE_MOD)) +obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero')) if FEATURE_FLAGS["SECP256K1_ZKP"]: obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function')) source_files.extend(SOURCE_MOD_SECP256K1_ZKP) @@ -775,8 +833,20 @@ def cargo_build(): features.append('universal_fw') features.append('ui') features.append('translations') + + if NEW_RENDERING: + features.append('new_rendering') + if PYOPT == '0': features.append('debug') + features.append('ui_debug') + if TREZOR_MODEL in ('T', 'T3T1', 'DISC1', 'DISC2'): + features.append('ui_blurring') + features.append('ui_jpeg_decoder') + + if NEW_RENDERING and TREZOR_MODEL in ('T3T1', 'DISC2'): + features.append('ui_image_buffer') + features.append('ui_overlay') features.extend(FEATURES_AVAILABLE) @@ -806,9 +876,9 @@ env.Append(LINKFLAGS=f' -L{RUST_LIBDIR}') env.Append(LINKFLAGS=f' -l{RUST_LIB}') -MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) BOOTLOADER_SUFFIX = MODEL_IDENTIFIER -if BOOTLOADER_QA: +if BOOTLOADER_QA or BOOTLOADER_DEVEL: BOOTLOADER_SUFFIX += '_qa' # select vendor header @@ -824,7 +894,7 @@ else: else: vendor = "trezor_signed_prod" -VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_{vendor}.bin' +VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_{vendor}.bin' if TREZOR_MODEL not in ('1',): @@ -842,7 +912,7 @@ if TREZOR_MODEL not in ('DISC1', 'DISC2'): env, 'bootloader', 'embed/firmware/bootloaders/bootloader.o', - f'embed/firmware/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', + f'embed/models/{MODEL_IDENTIFIER}/bootloaders/bootloader_{BOOTLOADER_SUFFIX}.bin', ) @@ -859,7 +929,7 @@ if CMAKELISTS != 0: env.Depends(program_elf, cmake_gen) env.Depends(program_elf, rust) -BINARY_NAME = f"build/firmware/firmware-{tools.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/firmware/firmware-{models.get_model_identifier(TREZOR_MODEL)}" if not EVERYTHING: BINARY_NAME += "-btconly" BINARY_NAME += "-" + tools.get_version('embed/firmware/version.h') diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 22a6626d03..91c9f5bf2b 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -1,12 +1,14 @@ # pylint: disable=E0602 import os -import tools +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) PRODUCTION = ARGUMENTS.get('PRODUCTION', '0') == '1' BOOTLOADER_DEVEL = ARGUMENTS.get('BOOTLOADER_DEVEL', '0') == '1' +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip prodtest build @@ -21,6 +23,9 @@ if TREZOR_MODEL in ('DISC1', 'DISC2'): FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mask", "optiga", "haptic"] +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") + CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [ @@ -28,22 +33,38 @@ CPPDEFINES_MOD = [ 'USE_INSECURE_PRNG', ] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO=None FONT_BIG=None -elif TREZOR_MODEL in ('T', 'T3T1'): + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None +elif TREZOR_MODEL in ('T',): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_Roboto_Bold_20' FONT_MONO=None FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None +elif TREZOR_MODEL in ('T3T1',): + FONT_NORMAL='Font_TTSatoshi_DemiBold_21' + FONT_DEMIBOLD=None + FONT_BOLD='Font_TTSatoshi_DemiBold_21' + FONT_MONO='Font_RobotoMono_Medium_21' + FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None # modtrezorcrypto CPPPATH_MOD += [ @@ -51,6 +72,9 @@ CPPPATH_MOD += [ 'vendor/trezor-storage', ] SOURCE_MOD += [ + 'vendor/trezor-storage/flash_area.c', +] +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/aes/aes_modes.c', 'vendor/trezor-crypto/aes/aesccm.c', 'vendor/trezor-crypto/aes/aescrypt.c', @@ -71,7 +95,6 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/secp256k1.c', 'vendor/trezor-crypto/sha2.c', 'vendor/trezor-crypto/tls_prf.c', - 'vendor/trezor-storage/flash_area.c', ] # modtrezorui @@ -82,9 +105,13 @@ CPPPATH_MOD += [ SOURCE_MOD += [ 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', + 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', 'embed/lib/mini_printf.c', 'embed/lib/qr-code-generator/qrcodegen.c', @@ -94,19 +121,34 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] + +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + SOURCE_MOD += [ + 'embed/lib/gfx_draw.c', + ] +else: + SOURCE_MOD += [ + 'embed/lib/display_draw.c', + ] + + # fonts tools.add_font('NORMAL', FONT_NORMAL, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment( ENV=os.environ, CFLAGS='%s -DPRODUCTION=%s' % (ARGUMENTS.get('CFLAGS', ''), ARGUMENTS.get('PRODUCTION', '0')), CPPDEFINES_IMPLICIT=[]) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] @@ -169,12 +211,12 @@ env.Replace( ) env.Replace( - HEADERTOOL='tools/headertool.py', + HEADERTOOL='headertool', ) env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_PRODTEST + SOURCE_HAL, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_PRODTEST + SOURCE_HAL, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( @@ -190,10 +232,11 @@ cmake_gen = env.Command( obj_program = [] obj_program.extend(env.Object(source=SOURCE_MOD)) +obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero')) obj_program.extend(env.Object(source=SOURCE_PRODTEST)) obj_program.extend(env.Object(source=SOURCE_HAL)) -MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) if (vh := ARGUMENTS.get("VENDOR_HEADER", None)): @@ -203,13 +246,13 @@ elif (vh := os.environ.get("VENDOR_HEADER", None)): # of vendor header which does not affect reproducibility of the build. Nonetheless, # we should figure out a cleaner way to pass in this argument, without having to teach # the Makefile about it. - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/{vh}' + VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/{vh}' elif PRODUCTION: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_prodtest_signed_prod.bin' + VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_prodtest_signed_prod.bin' elif BOOTLOADER_DEVEL: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin' + VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin' else: - VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_unsafe_signed_prod.bin' + VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_unsafe_signed_prod.bin' @@ -228,7 +271,7 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) -BINARY_NAME = f"build/prodtest/prodtest-{tools.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/prodtest/prodtest-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/prodtest/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() BINARY_NAME += "-dirty" if tools.get_git_modified() else "" diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 4772d45a95..3f87be288e 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -1,10 +1,11 @@ # pylint: disable=E0602 import os -import tools +import tools, models TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +HW_REVISION = ARGUMENTS.get('HW_REVISION', None) if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip reflash build @@ -23,29 +24,45 @@ CCFLAGS_MOD = '' CPPPATH_MOD = [] CPPDEFINES_MOD = [] SOURCE_MOD = [] +SOURCE_MOD_CRYPTO = [] CPPDEFINES_HAL = [] SOURCE_HAL = [] PATH_HAL = [] -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO=None FONT_BIG=None -elif TREZOR_MODEL in ('T', 'T3T1'): + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None +elif TREZOR_MODEL in ('T',): FONT_NORMAL=None FONT_DEMIBOLD=None FONT_BOLD='Font_Roboto_Bold_20' FONT_MONO=None FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None +elif TREZOR_MODEL in ('T3T1',): + FONT_NORMAL=None + FONT_DEMIBOLD=None + FONT_BOLD='Font_TTSatoshi_DemiBold_21' + FONT_MONO=None + FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB=None # modtrezorcrypto CPPPATH_MOD += [ 'vendor/trezor-crypto', 'vendor/trezor-storage', ] -SOURCE_MOD += [ +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/memzero.c', ] @@ -55,8 +72,9 @@ CPPPATH_MOD += [ ] SOURCE_MOD += [ 'embed/lib/colors.c', + 'embed/lib/display_draw.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', 'embed/lib/image.c', @@ -74,6 +92,9 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) env = Environment( ENV=os.environ, @@ -82,7 +103,7 @@ env = Environment( CPPDEFINES_IMPLICIT=[] ) -FEATURES_AVAILABLE = tools.configure_board(TREZOR_MODEL, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_HAL, PATH_HAL) FILE_SUFFIX= env.get('ENV')['SUFFIX'] LINKER_SCRIPT_SUFFIX= env.get('ENV')['LINKER_SCRIPT'] @@ -136,11 +157,11 @@ env.Replace( ) env.Replace( - HEADERTOOL='tools/headertool.py', + HEADERTOOL='headertool', ) env.Replace( - ALLSOURCES=SOURCE_MOD + SOURCE_REFLASH + SOURCE_HAL, + ALLSOURCES=SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_REFLASH + SOURCE_HAL, ALLDEFS=tools.get_defs_for_cmake(env['CPPDEFINES'] + env['CPPDEFINES_IMPLICIT'])) cmake_gen = env.Command( @@ -155,12 +176,13 @@ cmake_gen = env.Command( obj_program = [] obj_program += env.Object(source=SOURCE_MOD) +obj_program += env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero') obj_program += env.Object(source=SOURCE_REFLASH) obj_program += env.Object(source=SOURCE_HAL) -MODEL_IDENTIFIER = tools.get_model_identifier(TREZOR_MODEL) +MODEL_IDENTIFIER = models.get_model_identifier(TREZOR_MODEL) -VENDORHEADER = f'embed/vendorheader/{MODEL_IDENTIFIER}/vendorheader_' + ('unsafe_signed_dev.bin' if ARGUMENTS.get('PRODUCTION', '0') == '0' else 'satoshilabs_signed_prod.bin') +VENDORHEADER = f'embed/models/{MODEL_IDENTIFIER}/vendorheader/vendorheader_' + ('unsafe_signed_dev.bin' if ARGUMENTS.get('PRODUCTION', '0') == '0' else 'satoshilabs_signed_prod.bin') obj_program.extend( env.Command( @@ -177,7 +199,7 @@ program_elf = env.Command( '$LINK -o $TARGET $CCFLAGS $CFLAGS $LINKFLAGS $SOURCES -lc_nano -lgcc', ) -BINARY_NAME = f"build/reflash/reflash-{tools.get_model_identifier(TREZOR_MODEL)}" +BINARY_NAME = f"build/reflash/reflash-{models.get_model_identifier(TREZOR_MODEL)}" BINARY_NAME += "-" + tools.get_version('embed/reflash/version.h') BINARY_NAME += "-" + tools.get_git_revision_short_hash() BINARY_NAME += "-dirty" if tools.get_git_modified() else "" diff --git a/core/SConscript.unix b/core/SConscript.unix index 90fe0df537..d51ab2836a 100644 --- a/core/SConscript.unix +++ b/core/SConscript.unix @@ -2,14 +2,20 @@ # fmt: off import os -import tools +import tools, models BITCOIN_ONLY = ARGUMENTS.get('BITCOIN_ONLY', '0') EVERYTHING = BITCOIN_ONLY != '1' TREZOR_MODEL = ARGUMENTS.get('TREZOR_MODEL', 'T') -DMA2D = TREZOR_MODEL in ('T', 'T3T1') -OPTIGA = TREZOR_MODEL in ('R', 'T3T1') CMAKELISTS = int(ARGUMENTS.get('CMAKELISTS', 0)) +HW_REVISION ='emulator' +THP = ARGUMENTS.get('THP', '0') == '1' # Trezor-Host Protocol +NEW_RENDERING = ARGUMENTS.get('NEW_RENDERING', '1') == '1' or TREZOR_MODEL in ('T3T1',) + + +FEATURES_WANTED = ["input", "sd_card", "dma2d", "optiga", "sbu"] +if NEW_RENDERING: + FEATURES_WANTED.append("new_rendering") if TREZOR_MODEL in ('DISC1', 'DISC2'): # skip unix build @@ -29,27 +35,45 @@ FEATURE_FLAGS = { CCFLAGS_MOD = '' CPPPATH_MOD = [] +CPPDEFINES_HAL = [] +PATH_HAL = [] CPPDEFINES_MOD = [] SOURCE_MOD = [ 'vendor/micropython/extmod/vfs_posix_file.c', ] +SOURCE_MOD_CRYPTO = [] PYOPT = ARGUMENTS.get('PYOPT', '1') FROZEN = ARGUMENTS.get('TREZOR_EMULATOR_FROZEN', 0) RASPI = os.getenv('TREZOR_EMULATOR_RASPI') == '1' -if TREZOR_MODEL in ('1', 'R'): +if TREZOR_MODEL in ('1', 'R', 'T3B1'): FONT_NORMAL='Font_PixelOperator_Regular_8' FONT_DEMIBOLD='Font_Unifont_Bold_16' FONT_BOLD='Font_PixelOperator_Bold_8' FONT_MONO='Font_PixelOperatorMono_Regular_8' FONT_BIG='Font_Unifont_Regular_16' -elif TREZOR_MODEL in ('T', 'T3T1'): + FONT_NORMAL_UPPER='Font_PixelOperator_Regular_8_upper' + FONT_BOLD_UPPER='Font_PixelOperator_Bold_8_upper' + FONT_SUB=None +elif TREZOR_MODEL in ('T',): FONT_NORMAL='Font_TTHoves_Regular_21' FONT_DEMIBOLD='Font_TTHoves_DemiBold_21' - FONT_BOLD='Font_TTHoves_Bold_17' + FONT_BOLD=None FONT_MONO='Font_RobotoMono_Medium_20' FONT_BIG=None + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER='Font_TTHoves_Bold_17_upper' + FONT_SUB=None +elif TREZOR_MODEL in ('T3T1',): + FONT_NORMAL='Font_TTSatoshi_DemiBold_21' + FONT_DEMIBOLD='Font_TTSatoshi_DemiBold_21' + FONT_BOLD='Font_TTSatoshi_DemiBold_21' + FONT_MONO='Font_RobotoMono_Medium_21' + FONT_BIG='Font_TTSatoshi_DemiBold_42' + FONT_NORMAL_UPPER=None + FONT_BOLD_UPPER=None + FONT_SUB='Font_TTSatoshi_DemiBold_18' # modtrezorconfig CPPPATH_MOD += [ @@ -85,6 +109,8 @@ SOURCE_MOD += [ 'embed/extmod/trezorobj.c', 'embed/extmod/modtrezorcrypto/crc.c', 'embed/extmod/modtrezorcrypto/modtrezorcrypto.c', +] +SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/address.c', 'vendor/trezor-crypto/aes/aes_modes.c', 'vendor/trezor-crypto/aes/aescrypt.c', @@ -138,7 +164,7 @@ SOURCE_MOD += [ 'vendor/trezor-crypto/slip39_english.c', ] if EVERYTHING: - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/cardano.c', 'vendor/trezor-crypto/monero/base58.c', 'vendor/trezor-crypto/monero/serialize.c', @@ -158,18 +184,19 @@ if FEATURE_FLAGS["SECP256K1_ZKP"]: ('SECP256K1_CONTEXT_SIZE', '208'), 'USE_EXTERNAL_DEFAULT_CALLBACKS', ('ECMULT_GEN_PREC_BITS', '2'), - ('ECMULT_WINDOW_SIZE', '8'), + ('ECMULT_WINDOW_SIZE', '2'), 'ENABLE_MODULE_GENERATOR', 'ENABLE_MODULE_RECOVERY', 'ENABLE_MODULE_SCHNORRSIG', 'ENABLE_MODULE_EXTRAKEYS', + 'ENABLE_MODULE_ECDH', ] SOURCE_MOD_SECP256K1_ZKP = [ 'vendor/secp256k1-zkp/src/secp256k1.c', 'vendor/secp256k1-zkp/src/precomputed_ecmult.c', 'vendor/secp256k1-zkp/src/precomputed_ecmult_gen.c', ] - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/zkp_context.c', 'vendor/trezor-crypto/zkp_ecdsa.c', 'vendor/trezor-crypto/zkp_bip340.c', @@ -181,20 +208,21 @@ if FEATURE_FLAGS["AES_GCM"]: 'USE_AES_GCM', 'AES_VAR', ] - SOURCE_MOD += [ + SOURCE_MOD_CRYPTO += [ 'vendor/trezor-crypto/aes/gf128mul.c', 'vendor/trezor-crypto/aes/aesgcm.c', ] +if THP: + CPPDEFINES_MOD += ['USE_THP'] + SOURCE_MOD += [ + 'vendor/trezor-crypto/elligator2.c', + ] + # modtrezorio SOURCE_MOD += [ 'embed/extmod/modtrezorio/modtrezorio.c', ] -if TREZOR_MODEL in ('T', 'T3T1'): - SOURCE_MOD += [ - 'embed/extmod/modtrezorio/ff.c', - 'embed/extmod/modtrezorio/ffunicode.c', - ] # modtrezorui CPPPATH_MOD += [ @@ -205,10 +233,15 @@ SOURCE_MOD += [ 'embed/lib/buffers.c', 'embed/lib/colors.c', 'embed/lib/display_utils.c', - 'embed/lib/display.c', + 'embed/lib/error_handling.c', 'embed/lib/fonts/font_bitmap.c', 'embed/lib/fonts/fonts.c', + 'embed/lib/gfx_color.c', + 'embed/lib/gfx_bitblt_rgb565.c', + 'embed/lib/gfx_bitblt_rgba8888.c', + 'embed/lib/gfx_bitblt_mono8.c', 'embed/lib/image.c', + 'embed/lib/mini_printf.c', 'embed/lib/terminal.c', 'embed/lib/translations.c', 'embed/lib/unit_variant.c', @@ -217,25 +250,15 @@ SOURCE_MOD += [ 'vendor/micropython/lib/uzlib/tinflate.c', ] -if TREZOR_MODEL in ('1', ): - SOURCE_MOD += [ - 'embed/models/model_T1B1_layout.c', - ] -elif TREZOR_MODEL in ('T', ): - SOURCE_MOD += [ - 'embed/models/model_T2T1_layout.c', - ] -elif TREZOR_MODEL in ('R', ): +if NEW_RENDERING: SOURCE_MOD += [ - 'embed/models/model_T2B1_layout.c', + 'embed/lib/gfx_draw.c', ] -elif TREZOR_MODEL in ('T3T1', ): +else: SOURCE_MOD += [ - 'embed/models/model_T3T1_layout.c', + 'embed/lib/display_draw.c', ] - - CPPDEFINES_MOD += [ 'TREZOR_UI2', 'TRANSLATIONS', @@ -250,6 +273,9 @@ if FROZEN: if RASPI: CPPDEFINES_MOD += ['TREZOR_EMULATOR_RASPI'] +if NEW_RENDERING: + CPPDEFINES_MOD += ['NEW_RENDERING'] + # modtrezorutils SOURCE_MOD += [ 'embed/extmod/modtrezorutils/modtrezorutils.c', @@ -394,41 +420,32 @@ SOURCE_MICROPYTHON = [ SOURCE_UNIX = [ 'embed/trezorhal/unix/boot_args.c', 'embed/trezorhal/unix/common.c', - 'embed/trezorhal/unix/display-unix.c', - 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/flash_otp.c', + 'embed/trezorhal/unix/flash.c', 'embed/trezorhal/unix/random_delays.c', 'embed/trezorhal/unix/rng.c', + 'embed/trezorhal/unix/time_estimate.c', 'embed/trezorhal/unix/usb.c', - 'embed/trezorhal/unix/touch/touch.c', - 'embed/unix/main.c', 'embed/unix/main_main.c', + 'embed/unix/main.c', 'embed/unix/profile.c', - 'vendor/micropython/shared/runtime/gchelper_generic.c', 'vendor/micropython/ports/unix/alloc.c', 'vendor/micropython/ports/unix/gccollect.c', 'vendor/micropython/ports/unix/input.c', 'vendor/micropython/ports/unix/unix_mphal.c', + 'vendor/micropython/shared/runtime/gchelper_generic.c', ] -if TREZOR_MODEL in ('T', 'R', 'T3T1'): - SOURCE_UNIX += [ - 'embed/trezorhal/unix/sbu.c', - ] - -if OPTIGA: - SOURCE_UNIX += [ - 'embed/trezorhal/unix/optiga.c', - ] -if DMA2D: - CPPDEFINES_MOD += [ - 'USE_DMA2D', +if NEW_RENDERING: + SOURCE_MOD += [ + 'embed/trezorhal/unix/display_driver.c', + 'embed/trezorhal/xdisplay_legacy.c', ] - SOURCE_UNIX += [ - 'embed/lib/dma2d_emul.c', +else: + SOURCE_MOD += [ + 'embed/trezorhal/unix/display-unix.c', ] - TRANSLATION_DATA = [ "translations/en.json", "translations/order.json", @@ -441,6 +458,9 @@ tools.add_font('BOLD', FONT_BOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('DEMIBOLD', FONT_DEMIBOLD, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('MONO', FONT_MONO, CPPDEFINES_MOD, SOURCE_MOD) tools.add_font('BIG', FONT_BIG, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('NORMAL_UPPER', FONT_NORMAL_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('BOLD_UPPER', FONT_BOLD_UPPER, CPPDEFINES_MOD, SOURCE_MOD) +tools.add_font('SUB', FONT_SUB, CPPDEFINES_MOD, SOURCE_MOD) SOURCE_QSTR = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX @@ -452,24 +472,31 @@ else: env = Environment(ENV=os.environ, CFLAGS='%s -DCONFIDENTIAL= -DPYOPT=%s -DBITCOIN_ONLY=%s %s' % (ARGUMENTS.get('CFLAGS', ''), PYOPT, BITCOIN_ONLY, STATIC)) +FEATURES_AVAILABLE = models.configure_board(TREZOR_MODEL, HW_REVISION, FEATURES_WANTED, env, CPPDEFINES_HAL, SOURCE_UNIX, PATH_HAL) -if TREZOR_MODEL in ('T', 'T3T1'): +if TREZOR_MODEL in ('T',): UI_LAYOUT = 'UI_LAYOUT_TT' ui_layout_feature = 'model_tt' -elif TREZOR_MODEL in ('1', 'R'): +elif TREZOR_MODEL in ('1', 'R', 'T3B1'): UI_LAYOUT = 'UI_LAYOUT_TR' ui_layout_feature = 'model_tr' +elif TREZOR_MODEL in ('T3T1',): + UI_LAYOUT = 'UI_LAYOUT_MERCURY' + ui_layout_feature = 'model_mercury' else: raise ValueError('Unknown Trezor model') -if TREZOR_MODEL in ('T', 'T3T1'): + +if 'sd_card' in FEATURES_AVAILABLE: SDCARD = True - SOURCE_UNIX += [ - 'embed/trezorhal/unix/sdcard.c', - ] else: SDCARD = False +if 'optiga' in FEATURES_AVAILABLE: + OPTIGA = True +else: + OPTIGA = False + env.Tool('micropython') @@ -519,19 +546,6 @@ if ARGUMENTS.get('TREZOR_MEMPERF', '0') == '1': env.Replace( TREZOR_MODEL=TREZOR_MODEL, ) -if TREZOR_MODEL in ('T', 'R'): - CPU_MODEL = 'STM32F427xx' -elif TREZOR_MODEL in ('T3T1', ): - CPU_MODEL = 'STM32U585xx' -elif TREZOR_MODEL in ('DISC1', ): - CPU_MODEL = 'STM32F429xx' -elif TREZOR_MODEL in ('DISC2', ): - CPU_MODEL = 'STM32U5A9xx' -elif TREZOR_MODEL in ('1',): - CPU_MODEL = 'STM32F405xx' -else: - raise ValueError('Unknown Trezor model') - ALLPATHS=['.', 'embed/rust', 'embed/lib', @@ -543,7 +557,7 @@ ALLPATHS=['.', 'vendor/micropython', 'vendor/micropython/ports/unix', 'vendor/micropython/lib/mp-readline', - ] + CPPPATH_MOD + ] + CPPPATH_MOD + PATH_HAL env.Replace( CCFLAGS='$COPT ' @@ -554,16 +568,11 @@ env.Replace( LIBS=['m'], CPPPATH=ALLPATHS, CPPDEFINES=[ - CPU_MODEL, 'TREZOR_EMULATOR', 'TREZOR_MODEL_'+TREZOR_MODEL, - 'TREZOR_BOARD=\\"boards/board-unix.h\\"', - ('FLASH_BIT_ACCESS', '1'), - ('FLASH_BLOCK_WORDS', '1'), - 'MCU_TYPE='+CPU_MODEL, ('MP_CONFIGFILE', '\\"embed/unix/mpconfigport.h\\"'), UI_LAYOUT, - ] + CPPDEFINES_MOD, + ] + CPPDEFINES_MOD + CPPDEFINES_HAL, ASPPFLAGS='$CFLAGS $CCFLAGS', ) try: @@ -679,6 +688,12 @@ if FROZEN: SOURCE_PY_DIR + 'trezor/ui/layouts/tr/fido.py', ] if not EVERYTHING else [] )) + elif UI_LAYOUT == 'UI_LAYOUT_MERCURY': + SOURCE_PY.extend(Glob(SOURCE_PY_DIR + 'trezor/ui/layouts/mercury/*.py', + exclude=[ + SOURCE_PY_DIR + 'trezor/ui/layouts/mercury/fido.py', + ] if not EVERYTHING else [] + )) else: raise ValueError('Unknown layout') @@ -789,9 +804,10 @@ if FROZEN: source=SOURCE_PY, source_dir=SOURCE_PY_DIR, bitcoin_only=BITCOIN_ONLY, - backlight=TREZOR_MODEL in ('T', 'T3T1'), + backlight='backlight' in FEATURES_AVAILABLE, optiga=OPTIGA, ui_layout=UI_LAYOUT, + thp=THP, ) source_mpyc = env.FrozenCFile( @@ -805,8 +821,9 @@ if FROZEN: # obj_program = [] -source_files = SOURCE_MOD + SOURCE_MICROPYTHON + SOURCE_UNIX +source_files = SOURCE_MOD + SOURCE_MOD_CRYPTO + SOURCE_MICROPYTHON + SOURCE_UNIX obj_program.extend(env.Object(source=SOURCE_MOD)) +obj_program.extend(env.Object(source=SOURCE_MOD_CRYPTO, CCFLAGS='$CCFLAGS -ftrivial-auto-var-init=zero')) if FEATURE_FLAGS["SECP256K1_ZKP"]: obj_program.extend(env.Object(source=SOURCE_MOD_SECP256K1_ZKP, CCFLAGS='$CCFLAGS -Wno-unused-function')) source_files.extend(SOURCE_MOD_SECP256K1_ZKP) @@ -860,16 +877,24 @@ def cargo_build(): features.append('universal_fw') features.append('ui') features.append('translations') + if PYOPT == '0': features.append('debug') - if DMA2D: - features.append('dma2d') + + features.extend(FEATURES_AVAILABLE) if TREZOR_MODEL in ('T', 'T3T1'): - features.append('touch') - features.append('sd_card') - if TREZOR_MODEL in ('R', '1'): - features.append('button') + features.append('ui_blurring') + features.append('ui_jpeg_decoder') + + if NEW_RENDERING and TREZOR_MODEL in ('T3T1', ): + features.append('ui_image_buffer') + features.append('ui_overlay') + + if NEW_RENDERING: + features.append('new_rendering') + + env.get('ENV')['TREZOR_MODEL'] = TREZOR_MODEL bindgen_macros = tools.get_bindgen_defines(env.get("CPPDEFINES"), ALLPATHS) diff --git a/core/embed/boardloader/CHANGELOG.md b/core/embed/boardloader/CHANGELOG.md index 344b16ee95..e766ee74a2 100644 --- a/core/embed/boardloader/CHANGELOG.md +++ b/core/embed/boardloader/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.1.3 [July 2024] + +### Added +- [T3B1] Added support for T3B1. + + ## 2.1.2 [April 2024] ### Added diff --git a/core/embed/boardloader/main.c b/core/embed/boardloader/main.c index d5dedfe026..6444fff90d 100644 --- a/core/embed/boardloader/main.c +++ b/core/embed/boardloader/main.c @@ -21,9 +21,11 @@ #include TREZOR_BOARD #include "board_capabilities.h" +#include "buffers.h" #include "common.h" #include "compiler_traits.h" #include "display.h" +#include "display_draw.h" #include "fault_handlers.h" #include "flash.h" #include "image.h" @@ -42,8 +44,17 @@ #include "hash_processor.h" #endif +#ifdef USE_DMA2D +#ifdef NEW_RENDERING +#include "dma2d_bitblt.h" +#else +#include "dma2d.h" +#endif +#endif + #include "lowlevel.h" #include "model.h" +#include "monoctr.h" #include "version.h" #include "memzero.h" @@ -66,45 +77,17 @@ static const uint8_t * const BOARDLOADER_KEYS[] = { #endif }; -#ifdef STM32U5 -uint8_t get_bootloader_min_version(void) { - const uint8_t *counter_addr = - flash_area_get_address(&SECRET_AREA, SECRET_MONOTONIC_COUNTER_OFFSET, - SECRET_MONOTONIC_COUNTER_LEN); - - ensure((counter_addr != NULL) * sectrue, "counter_addr is NULL"); - - int counter = 0; - - for (int i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) { - secbool not_cleared = sectrue; - for (int j = 0; j < 16; j++) { - if (counter_addr[i * 16 + j] != 0xFF) { - not_cleared = secfalse; - break; - } - } - - if (not_cleared != sectrue) { - counter++; - } else { - break; - } - } - - return counter; +static uint8_t get_bootloader_min_version(void) { + uint8_t version = 0; + ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &version), "monoctr read"); + return version; } -void write_bootloader_min_version(uint8_t version) { +static void write_bootloader_min_version(uint8_t version) { if (version > get_bootloader_min_version()) { - for (int i = 0; i < version; i++) { - uint32_t data[4] = {0}; - secret_write((uint8_t *)data, SECRET_MONOTONIC_COUNTER_OFFSET + i * 16, - 16); - } + ensure(monoctr_write(MONOCTR_BOOTLOADER_VERSION, version), "monoctr write"); } } -#endif struct BoardCapabilities capabilities __attribute__((section(".capabilities_section"))) = { @@ -165,9 +148,19 @@ static uint32_t check_sdcard(void) { _Static_assert(IMAGE_CHUNK_SIZE >= BOOTLOADER_IMAGE_MAXSIZE, "BOOTLOADER IMAGE MAXSIZE too large for IMAGE_CHUNK_SIZE"); - if (sectrue != (check_single_hash( - hdr->hashes, ((const uint8_t *)sdcard_buf) + hdr->hdrlen, - hdr->codelen))) { + const uint32_t headers_end_offset = hdr->hdrlen; + const uint32_t code_start_offset = IMAGE_CODE_ALIGN(headers_end_offset); + + for (uint32_t i = headers_end_offset; i < code_start_offset; i++) { + if (((uint8_t *)sdcard_buf)[i] != 0) { + return 0; + } + } + + if (sectrue != + (check_single_hash(hdr->hashes, + (const uint8_t *)sdcard_buf + code_start_offset, + hdr->codelen))) { return 0; } @@ -177,11 +170,9 @@ static uint32_t check_sdcard(void) { } } -#ifdef STM32U5 if (hdr->monotonic < get_bootloader_min_version()) { return 0; } -#endif return hdr->codelen; } @@ -279,6 +270,10 @@ int main(void) { hash_processor_init(); #endif +#ifdef USE_DMA2D + dma2d_init(); +#endif + display_init(); display_clear(); display_refresh(); @@ -286,7 +281,6 @@ int main(void) { #if defined USE_SD_CARD sdcard_init(); -#ifdef STM32U5 // If the bootloader is being updated from SD card, we need to preserve the // monotonic counter from the old bootloader. This is in case that the old // bootloader did not have the chance yet to write its monotonic counter to @@ -303,7 +297,6 @@ int main(void) { check_image_contents(old_hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA))) { write_bootloader_min_version(old_hdr->monotonic); } -#endif if (check_sdcard()) { return copy_sdcard() == sectrue ? 0 : 3; @@ -324,21 +317,19 @@ int main(void) { ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE, &BOOTLOADER_AREA), "invalid bootloader hash"); -#ifdef STM32U5 uint8_t bld_min_version = get_bootloader_min_version(); ensure((hdr->monotonic >= bld_min_version) * sectrue, "BOOTLOADER DOWNGRADED"); // Write the bootloader version to the secret area. // This includes the version of bootloader potentially updated from SD card. write_bootloader_min_version(hdr->monotonic); -#endif ensure_compatible_settings(); mpu_config_off(); // g_boot_command is preserved on STM32U5 - jump_to(BOOTLOADER_START + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(BOOTLOADER_START + IMAGE_HEADER_SIZE)); return 0; } diff --git a/core/embed/boardloader/memory_stm32u5a.ld b/core/embed/boardloader/memory_stm32u5a.ld index 756b43b143..f91099d006 100644 --- a/core/embed/boardloader/memory_stm32u5a.ld +++ b/core/embed/boardloader/memory_stm32u5a.ld @@ -46,7 +46,7 @@ boot_args_start = ORIGIN(BOOT_ARGS); boot_args_end = ORIGIN(BOOT_ARGS) + LENGTH(BOOT_ARGS); SECTIONS { - .vector_table : ALIGN(512) { + .vector_table : ALIGN(1024) { KEEP(*(.vector_table)); } >FLASH AT>FLASH diff --git a/core/embed/boardloader/version.h b/core/embed/boardloader/version.h index c63395c08c..4af28c65c2 100644 --- a/core/embed/boardloader/version.h +++ b/core/embed/boardloader/version.h @@ -1,4 +1,4 @@ #define VERSION_MAJOR 2 #define VERSION_MINOR 1 -#define VERSION_PATCH 3 +#define VERSION_PATCH 4 #define VERSION_BUILD 0 diff --git a/core/embed/bootloader/CHANGELOG.md b/core/embed/bootloader/CHANGELOG.md index 0e156e9156..1377537ce5 100644 --- a/core/embed/bootloader/CHANGELOG.md +++ b/core/embed/bootloader/CHANGELOG.md @@ -4,6 +4,34 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## 2.1.8 [September 2024] + +### Added +- Added firmware downgrade protection [#4133] + +### Changed +- Require confirmation when installing non-full trust firmware image on empty device [#3709] +- Fix incorrect error message when installing firmware for different model. [#4081] +- [T3B1, T3T1] Added bootloader unlock mechanism to U5 models [#4133] + +### Fixed +- [T3B1] UI adjustments: fix icon on warning screen, replace empty logo with full during boot [#4140] + +## 2.1.7 [July 2024] + +### Added +- [T3B1] Added support for T3B1. + + +## 2.1.6 [May 2024] + +### Added +- Added `unit_packaging` field to `Features`. [#3711] + +### Changed +- [T3T1] Changed USB manufacturer string to "Trezor Company" and product string to "Trezor Safe 5" in the USB descriptor strings. [#3770] + + ## 2.1.5 [April 2024] ### Added @@ -129,3 +157,9 @@ Internal only release for Model R prototypes. [#3303]: https://github.com/trezor/trezor-firmware/pull/3303 [#3370]: https://github.com/trezor/trezor-firmware/pull/3370 [#3429]: https://github.com/trezor/trezor-firmware/pull/3429 +[#3709]: https://github.com/trezor/trezor-firmware/pull/3709 +[#3711]: https://github.com/trezor/trezor-firmware/pull/3711 +[#3770]: https://github.com/trezor/trezor-firmware/pull/3770 +[#4081]: https://github.com/trezor/trezor-firmware/pull/4081 +[#4133]: https://github.com/trezor/trezor-firmware/pull/4133 +[#4140]: https://github.com/trezor/trezor-firmware/pull/4140 diff --git a/core/embed/bootloader/bootui.c b/core/embed/bootloader/bootui.c index ae5937073f..ab18a52f01 100644 --- a/core/embed/bootloader/bootui.c +++ b/core/embed/bootloader/bootui.c @@ -22,8 +22,11 @@ #include TREZOR_BOARD #include "bootui.h" +#include "colors.h" #include "display.h" +#include "display_draw.h" #include "display_utils.h" +#include "fonts/fonts.h" #ifdef TREZOR_EMULATOR #include "emulator.h" #else @@ -49,7 +52,7 @@ #define COLOR_BL_GRAY COLOR_BL_FG #endif -#ifndef TREZOR_MODEL_R +#if !defined TREZOR_MODEL_R && !defined TREZOR_MODEL_T3B1 #define BOOT_WAIT_HEIGHT 25 #define BOOT_WAIT_Y_TOP (DISPLAY_RESY - BOOT_WAIT_HEIGHT) #else @@ -57,6 +60,8 @@ #define BOOT_WAIT_Y_TOP (DISPLAY_RESY - BOOT_WAIT_HEIGHT) #endif +#define TOIF_LENGTH(ptr) ((*(uint32_t *)((ptr) + 8)) + 12) + // common shared functions static void format_ver(const char *format, uint32_t version, char *buffer, @@ -69,18 +74,22 @@ static void format_ver(const char *format, uint32_t version, char *buffer, // boot UI +#ifndef NEW_RENDERING static uint16_t boot_background; +#endif + static bool initial_setup = true; void ui_set_initial_setup(bool initial) { initial_setup = initial; } -void ui_screen_boot(const vendor_header *const vhdr, - const image_header *const hdr) { - const int show_string = ((vhdr->vtrust & VTRUST_STRING) == 0); - if ((vhdr->vtrust & VTRUST_RED) == 0) { - boot_background = COLOR_BL_FAIL; - } else { +#ifndef NEW_RENDERING +static void ui_screen_boot_old(const vendor_header *const vhdr, + const image_header *const hdr) { + const int show_string = ((vhdr->vtrust & VTRUST_NO_STRING) == 0); + if ((vhdr->vtrust & VTRUST_NO_RED) != 0) { boot_background = COLOR_BLACK; + } else { + boot_background = COLOR_BL_FAIL; } const uint8_t *vimg = vhdr->vimg; @@ -88,12 +97,12 @@ void ui_screen_boot(const vendor_header *const vhdr, display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, boot_background); -#ifndef TREZOR_MODEL_R +#if !defined TREZOR_MODEL_R && !defined TREZOR_MODEL_T3B1 int image_top = show_string ? 30 : (DISPLAY_RESY - 120) / 2; // check whether vendor image is 120x120 if (memcmp(vimg, "TOIF\x78\x00\x78\x00", 8) == 0) { - uint32_t datalen = *(uint32_t *)(vimg + 8); - display_image((DISPLAY_RESX - 120) / 2, image_top, vimg, datalen + 12); + uint32_t datalen = TOIF_LENGTH(vimg); + display_image((DISPLAY_RESX - 120) / 2, image_top, vimg, datalen); } if (show_string) { @@ -108,8 +117,8 @@ void ui_screen_boot(const vendor_header *const vhdr, #else // check whether vendor image is 24x24 if (memcmp(vimg, "TOIG\x18\x00\x18\x00", 8) == 0) { - uint32_t datalen = *(uint32_t *)(vimg + 8); - display_icon((DISPLAY_RESX - 22) / 2, 0, vimg, datalen + 12, COLOR_BL_BG, + uint32_t datalen = TOIF_LENGTH(vimg); + display_icon((DISPLAY_RESX - 22) / 2, 0, vimg, datalen, COLOR_BL_BG, boot_background); } @@ -127,9 +136,11 @@ void ui_screen_boot(const vendor_header *const vhdr, display_pixeldata_dirty(); display_refresh(); } +#endif -void ui_screen_boot_wait(int wait_seconds) { - char wait_str[16]; +#ifndef NEW_RENDERING +static void ui_screen_boot_wait(int wait_seconds) { + char wait_str[32]; mini_snprintf(wait_str, sizeof(wait_str), "starting in %d s", wait_seconds); display_bar(0, BOOT_WAIT_Y_TOP, DISPLAY_RESX, BOOT_WAIT_HEIGHT, boot_background); @@ -138,22 +149,23 @@ void ui_screen_boot_wait(int wait_seconds) { display_pixeldata_dirty(); display_refresh(); } +#endif #if defined USE_TOUCH #include "touch.h" void ui_click(void) { // flush touch events if any - while (touch_read()) { + while (touch_get_event()) { } // wait for TOUCH_START - while ((touch_read() & TOUCH_START) == 0) { + while ((touch_get_event() & TOUCH_START) == 0) { } // wait for TOUCH_END - while ((touch_read() & TOUCH_END) == 0) { + while ((touch_get_event() & TOUCH_END) == 0) { } // flush touch events if any - while (touch_read()) { + while (touch_get_event()) { } } @@ -179,7 +191,8 @@ void ui_click(void) { #error "No input method defined" #endif -void ui_screen_boot_click(void) { +#ifndef NEW_RENDERING +static void ui_screen_boot_click(void) { display_bar(0, BOOT_WAIT_Y_TOP, DISPLAY_RESX, BOOT_WAIT_HEIGHT, boot_background); bld_continue_label(boot_background); @@ -187,6 +200,33 @@ void ui_screen_boot_click(void) { display_refresh(); ui_click(); } +#endif + +#ifdef NEW_RENDERING +void ui_screen_boot(const vendor_header *const vhdr, + const image_header *const hdr, int wait) { + bool show_string = ((vhdr->vtrust & VTRUST_NO_STRING) == 0); + const char *vendor_str = show_string ? vhdr->vstr : NULL; + const size_t vendor_str_len = show_string ? vhdr->vstr_len : 0; + bool red_screen = ((vhdr->vtrust & VTRUST_NO_RED) == 0); + uint32_t vimg_len = TOIF_LENGTH(vhdr->vimg); + + screen_boot(red_screen, vendor_str, vendor_str_len, hdr->version, vhdr->vimg, + vimg_len, wait); +} +#else // NEW_RENDERING + +void ui_screen_boot(const vendor_header *const vhdr, + const image_header *const hdr, int wait) { + if (wait == 0) { + ui_screen_boot_old(vhdr, hdr); + } else if (wait > 0) { + ui_screen_boot_wait(wait); + } else { + ui_screen_boot_click(); + } +} +#endif // welcome UI @@ -211,14 +251,17 @@ uint32_t ui_screen_menu(secbool firmware_present) { uint32_t ui_screen_install_confirm(const vendor_header *const vhdr, const image_header *const hdr, secbool should_keep_seed, - secbool is_newvendor, int version_cmp) { + secbool is_newvendor, secbool is_newinstall, + int version_cmp) { uint8_t fingerprint[32]; char ver_str[64]; get_image_fingerprint(hdr, fingerprint); format_ver("%d.%d.%d", hdr->version, ver_str, sizeof(ver_str)); return screen_install_confirm(vhdr->vstr, vhdr->vstr_len, ver_str, fingerprint, should_keep_seed == sectrue, - is_newvendor == sectrue, version_cmp); + + is_newvendor == sectrue, + is_newinstall == sectrue, version_cmp); } void ui_screen_install_start() { diff --git a/core/embed/bootloader/bootui.h b/core/embed/bootloader/bootui.h index c63a6ffa32..4b29f01532 100644 --- a/core/embed/bootloader/bootui.h +++ b/core/embed/bootloader/bootui.h @@ -34,10 +34,22 @@ typedef enum { SCREEN_WELCOME = 5, } screen_t; +// Displays a warning screeen before jumping to the untrusted firmware +// +// Shows vendor image, vendor string and firmware version +// and optional message to the user (see `wait` argument) +// +// `wait` argument specifies a message to the user +// 0 do not show any message +// > 0 show a message like "starting in %d s" +// < 0 show a message like "press button to continue" void ui_screen_boot(const vendor_header* const vhdr, - const image_header* const hdr); -void ui_screen_boot_wait(int wait_seconds); -void ui_screen_boot_click(void); + const image_header* const hdr, int wait); + +// Waits until the user confirms the untrusted firmware +// +// Implementation is device specific - it wait's until +// the user presses a button, touches the display void ui_click(void); void ui_screen_welcome(void); @@ -50,7 +62,8 @@ uint32_t ui_screen_menu(secbool firmware_present); uint32_t ui_screen_install_confirm(const vendor_header* const vhdr, const image_header* const hdr, secbool shold_keep_seed, - secbool is_newvendor, int version_cmp); + secbool is_newvendor, secbool is_newinstall, + int version_cmp); void ui_screen_install_start(); void ui_screen_install_progress_erase(int pos, int len); void ui_screen_install_progress_upload(int pos); diff --git a/core/embed/bootloader/emulator.c b/core/embed/bootloader/emulator.c index 1ad001af1f..fb570b0c9b 100644 --- a/core/embed/bootloader/emulator.c +++ b/core/embed/bootloader/emulator.c @@ -22,6 +22,9 @@ uint8_t *FIRMWARE_START = 0; void set_core_clock(int) {} +// used in fw emulator to raise python exception on exit +void __attribute__((noreturn)) main_clean_exit() { exit(3); } + int bootloader_main(void); // assuming storage is single subarea @@ -62,20 +65,20 @@ bool load_firmware(const char *filename, uint8_t *hash) { size_t read = fread(buffer, 1, sizeof(buffer), file); fclose(file); if (read != sizeof(buffer)) { - printf("File '%s' does not contain a valid firmware image.\n"); + printf("File '%s' does not contain a valid firmware image.\n", filename); return false; } // read vendor and image header vendor_header vhdr; if (sectrue != read_vendor_header(buffer, &vhdr)) { - printf("File '%s' does not contain a valid vendor header.\n"); + printf("File '%s' does not contain a valid vendor header.\n", filename); return false; } const image_header *hdr = read_image_header( buffer + vhdr.hdrlen, FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE); if (hdr != (const image_header *)(buffer + vhdr.hdrlen)) { - printf("File '%s' does not contain a valid firmware image.\n"); + printf("File '%s' does not contain a valid firmware image.\n", filename); return false; } @@ -88,28 +91,8 @@ bool load_firmware(const char *filename, uint8_t *hash) { return true; } -__attribute__((noreturn)) void display_error_and_die(const char *message, - const char *title, - const char *footer) { - if (footer == NULL) { - footer = "PLEASE VISIT\nTREZOR.IO/RSOD"; - } - if (title == NULL) { - title = "INTERNAL ERROR"; - } - display_init(); - display_backlight(180); - screen_fatal_error_rust(title, message, footer); -#if USE_TOUCH - printf("Click screen to exit.\n"); -#elif USE_BUTTON - printf("Press both buttons to exit.\n"); -#endif - ui_click(); - exit(0); -} - __attribute__((noreturn)) int main(int argc, char **argv) { + display_init(); flash_init(); flash_otp_init(); @@ -174,7 +157,7 @@ __attribute__((noreturn)) int main(int argc, char **argv) { } else { message = "No message specified"; } - display_error_and_die(message, title, footer); + error_shutdown_ex(title, message, footer); } // write variant to OTP @@ -184,35 +167,26 @@ __attribute__((noreturn)) int main(int argc, char **argv) { bootloader_main(); hal_delay(3000); - jump_to(NULL); + jump_to(0); } -void display_set_little_endian(void) {} - -void display_reinit(void) {} - void mpu_config_bootloader(void) {} void mpu_config_off(void) {} -__attribute__((noreturn)) void jump_to(void *addr) { +__attribute__((noreturn)) void jump_to(uint32_t address) { bool storage_is_erased = storage_empty(&STORAGE_AREAS[0]) && storage_empty(&STORAGE_AREAS[1]); if (storage_is_erased) { printf("STORAGE WAS ERASED\n"); - screen_fatal_error_rust("BOOTLOADER EXIT", "Jumped to firmware", - "STORAGE WAS ERASED"); + error_shutdown_ex("BOOTLOADER EXIT", "Jumped to firmware", + "STORAGE WAS ERASED"); } else { printf("storage was retained\n"); - screen_fatal_error_rust("BOOTLOADER EXIT", "Jumped to firmware", - "STORAGE WAS RETAINED"); + error_shutdown_ex("BOOTLOADER EXIT", "Jumped to firmware", + "STORAGE WAS RETAINED"); } - display_backlight(180); - hal_delay(3000); - exit(0); } void ensure_compatible_settings(void) {} - -void main_clean_exit(int code) { exit(code); } diff --git a/core/embed/bootloader/emulator.h b/core/embed/bootloader/emulator.h index d73b8bed4a..9facab471c 100644 --- a/core/embed/bootloader/emulator.h +++ b/core/embed/bootloader/emulator.h @@ -16,7 +16,7 @@ void set_core_clock(int); void mpu_config_bootloader(void); void mpu_config_off(void); void display_set_little_endian(void); -void jump_to(void *addr); +void jump_to(uint32_t address); void ensure_compatible_settings(void); #endif diff --git a/core/embed/bootloader/header.S b/core/embed/bootloader/header.S index 9014961835..8945f4cd29 100644 --- a/core/embed/bootloader/header.S +++ b/core/embed/bootloader/header.S @@ -26,7 +26,7 @@ g_header: .byte FIX_VERSION_BUILD // fix_vbuild .word HW_MODEL // type of the designated hardware .byte HW_REVISION // revision of the designated hardware - .byte VERSION_MONOTONIC // monotonic version of the binary + .byte BOOTLOADER_MONOTONIC_VERSION // monotonic version of the binary . = . + 2 // reserved . = . + 512 // hash1 ... hash16 . = . + 415 // reserved diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index 180bef9433..136bd28c71 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -35,8 +35,12 @@ #include "secret.h" #ifdef USE_DMA2D +#ifdef NEW_RENDERING +#include "dma2d_bitblt.h" +#else #include "dma2d.h" #endif +#endif #ifdef USE_I2C #include "i2c.h" #endif @@ -65,14 +69,15 @@ #include "bootui.h" #include "messages.h" +#include "monoctr.h" #include "rust_ui.h" #include "unit_variant.h" +#include "version_check.h" #ifdef TREZOR_EMULATOR #include "emulator.h" #else #include "compiler_traits.h" -#include "mini_printf.h" #include "mpu.h" #include "platform.h" #endif @@ -98,8 +103,8 @@ static void usb_init_all(secbool usb21_landing) { .vendor_id = 0x1209, .product_id = 0x53C0, .release_num = 0x0200, - .manufacturer = "SatoshiLabs", - .product = "TREZOR", + .manufacturer = MODEL_USB_MANUFACTURER, + .product = MODEL_USB_PRODUCT, .serial_number = "000000000000000000000000", .interface = "TREZOR Interface", .usb21_enabled = sectrue, @@ -113,8 +118,8 @@ static void usb_init_all(secbool usb21_landing) { #ifdef TREZOR_EMULATOR .emu_port = 21324, #else - .ep_in = USB_EP_DIR_IN | 0x01, - .ep_out = USB_EP_DIR_OUT | 0x01, + .ep_in = 0x01, + .ep_out = 0x01, #endif .subclass = 0, .protocol = 0, @@ -123,11 +128,11 @@ static void usb_init_all(secbool usb21_landing) { .polling_interval = 1, }; - usb_init(&dev_info); + ensure(usb_init(&dev_info), NULL); ensure(usb_webusb_add(&webusb_info), NULL); - usb_start(); + ensure(usb_start(), NULL); } static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, @@ -166,7 +171,6 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, if (INPUT_CANCEL == response) { send_user_abort(USB_IFACE_NUM, "Wipe cancelled"); hal_delay(100); - usb_stop(); usb_deinit(); return RETURN_TO_MENU; } @@ -175,13 +179,11 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, if (r < 0) { // error screen_wipe_fail(); hal_delay(100); - usb_stop(); usb_deinit(); return SHUTDOWN; } else { // success screen_wipe_success(); hal_delay(100); - usb_stop(); usb_deinit(); return SHUTDOWN; } @@ -193,16 +195,15 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf); if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort if (r == UPLOAD_ERR_BOOTLOADER_LOCKED) { - secret_show_install_restricted_screen(); + // This function does not return + show_install_restricted_screen(); } else { ui_screen_fail(); } - usb_stop(); usb_deinit(); return SHUTDOWN; } else if (r == UPLOAD_ERR_USER_ABORT) { hal_delay(100); - usb_stop(); usb_deinit(); return RETURN_TO_MENU; } else if (r == 0) { // last chunk received @@ -214,7 +215,6 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(1000); ui_screen_done(1, secfalse); hal_delay(1000); - usb_stop(); usb_deinit(); return CONTINUE_TO_FIRMWARE; } @@ -222,20 +222,18 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr, case MessageType_MessageType_GetFeatures: process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr); break; -#if defined USE_OPTIGA && !defined STM32U5 +#if defined USE_OPTIGA case MessageType_MessageType_UnlockBootloader: response = ui_screen_unlock_bootloader_confirm(); if (INPUT_CANCEL == response) { send_user_abort(USB_IFACE_NUM, "Bootloader unlock cancelled"); hal_delay(100); - usb_stop(); usb_deinit(); return RETURN_TO_MENU; } process_msg_UnlockBootloader(USB_IFACE_NUM, msg_size, buf); screen_unlock_bootloader_success(); hal_delay(100); - usb_stop(); usb_deinit(); return SHUTDOWN; break; @@ -264,37 +262,7 @@ static secbool check_vendor_header_lock(const vendor_header *const vhdr) { return sectrue * (0 == memcmp(lock, hash, 32)); } -// protection against bootloader downgrade - -#if PRODUCTION && !defined STM32U5 - -static void check_bootloader_version(void) { - uint8_t bits[FLASH_OTP_BLOCK_SIZE]; - for (int i = 0; i < FLASH_OTP_BLOCK_SIZE * 8; i++) { - if (i < VERSION_MONOTONIC) { - bits[i / 8] &= ~(1 << (7 - (i % 8))); - } else { - bits[i / 8] |= (1 << (7 - (i % 8))); - } - } - ensure(flash_otp_write(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits, - FLASH_OTP_BLOCK_SIZE), - NULL); - - uint8_t bits2[FLASH_OTP_BLOCK_SIZE]; - ensure(flash_otp_read(FLASH_OTP_BLOCK_BOOTLOADER_VERSION, 0, bits2, - FLASH_OTP_BLOCK_SIZE), - NULL); - - ensure(sectrue * (0 == memcmp(bits, bits2, FLASH_OTP_BLOCK_SIZE)), - "Bootloader downgrade protection"); -} - -#endif - -void failed_jump_to_firmware(void) { - error_shutdown("INTERNAL ERROR", "(glitch)"); -} +void failed_jump_to_firmware(void) { error_shutdown("(glitch)"); } void real_jump_to_firmware(void) { const image_header *hdr = NULL; @@ -321,24 +289,29 @@ void real_jump_to_firmware(void) { ensure(check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub), "Firmware is corrupted"); + ensure(check_firmware_min_version(hdr->monotonic), + "Firmware downgrade protection"); + ensure_firmware_min_version(hdr->monotonic); + ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, &FIRMWARE_AREA), "Firmware is corrupted"); secret_prepare_fw( - ((vhdr.vtrust & VTRUST_SECRET) == VTRUST_SECRET_ALLOW) * sectrue, - ((vhdr.vtrust & VTRUST_ALL) == VTRUST_ALL) * sectrue); + ((vhdr.vtrust & VTRUST_SECRET_MASK) == VTRUST_SECRET_ALLOW) * sectrue, + ((vhdr.vtrust & VTRUST_NO_WARNING) == VTRUST_NO_WARNING) * sectrue); - // if all VTRUST flags are unset = ultimate trust => skip the procedure - if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) { + // if all warnings are disabled in VTRUST flags then skip the procedure + if ((vhdr.vtrust & VTRUST_NO_WARNING) != VTRUST_NO_WARNING) { ui_fadeout(); - ui_screen_boot(&vhdr, hdr); + ui_screen_boot(&vhdr, hdr, 0); ui_fadein(); - int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT; + // The delay is encoded in bitwise complement form. + int delay = (vhdr.vtrust & VTRUST_WAIT_MASK) ^ VTRUST_WAIT_MASK; if (delay > 1) { while (delay > 0) { - ui_screen_boot_wait(delay); + ui_screen_boot(&vhdr, hdr, delay); hal_delay(1000); delay--; } @@ -346,8 +319,9 @@ void real_jump_to_firmware(void) { hal_delay(1000); } - if ((vhdr.vtrust & VTRUST_CLICK) == 0) { - ui_screen_boot_click(); + if ((vhdr.vtrust & VTRUST_NO_CLICK) == 0) { + ui_screen_boot(&vhdr, hdr, -1); + ui_click(); } ui_screen_boot_stage_1(false); @@ -356,11 +330,8 @@ void real_jump_to_firmware(void) { display_finish_actions(); ensure_compatible_settings(); - // mpu_config_firmware(); - // jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); - mpu_config_off(); - jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); } #ifdef STM32U5 @@ -406,7 +377,6 @@ int bootloader_main(void) { unit_variant_init(); #ifdef USE_TOUCH - touch_power_on(); #ifdef TREZOR_MODEL_T3T1 // on T3T1, tester needs to run without touch, so making an exception // until unit variant is written in OTP @@ -441,6 +411,8 @@ int bootloader_main(void) { volatile secbool vhdr_lock_ok = secfalse; volatile secbool img_hdr_ok = secfalse; volatile secbool model_ok = secfalse; + volatile secbool signatures_ok = secfalse; + volatile secbool version_ok = secfalse; volatile secbool header_present = secfalse; volatile secbool firmware_present = secfalse; volatile secbool firmware_present_backup = secfalse; @@ -467,12 +439,22 @@ int bootloader_main(void) { if (sectrue == img_hdr_ok) { model_ok = check_image_model(hdr); } + if (sectrue == model_ok) { - header_present = + signatures_ok = check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub); } + if (sectrue == signatures_ok) { + version_ok = check_firmware_min_version(hdr->monotonic); + } + + if (sectrue == version_ok) { + header_present = version_ok; + } + if (sectrue == header_present) { + ensure_firmware_min_version(hdr->monotonic); firmware_present = check_image_contents( hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen, &FIRMWARE_AREA); firmware_present_backup = firmware_present; @@ -496,12 +478,12 @@ int bootloader_main(void) { #if PRODUCTION && !defined STM32U5 // for STM32U5, this check is moved to boardloader - check_bootloader_version(); + ensure_bootloader_min_version(); #endif switch (bootargs_get_command()) { case BOOT_COMMAND_STOP_AND_WAIT: - // firmare requested to stay in bootloader + // firmware requested to stay in bootloader stay_in_bootloader = sectrue; break; case BOOT_COMMAND_INSTALL_UPGRADE: @@ -522,17 +504,22 @@ int bootloader_main(void) { uint32_t touched = 0; #ifdef USE_TOUCH if (firmware_present == sectrue && stay_in_bootloader != sectrue) { - touch_wait_until_ready(); + // Wait until the touch controller is ready + // (on hardware this may take a while) + while (touch_ready() != sectrue) { + hal_delay(1); + } +#ifdef TREZOR_EMULATOR + hal_delay(500); +#endif + // Give the touch controller time to report events + // if someone touches the screen for (int i = 0; i < 10; i++) { - touched = touch_is_detected() | touch_read(); - if (touched) { + if (touch_activity() == sectrue) { + touched = 1; break; } -#ifdef TREZOR_EMULATOR - hal_delay(25); -#else - hal_delay_us(1000); -#endif + hal_delay(5); } } #elif defined USE_BUTTON diff --git a/core/embed/bootloader/memory_stm32f4.ld b/core/embed/bootloader/memory_stm32f4.ld index 3662808146..392c9a1d8e 100644 --- a/core/embed/bootloader/memory_stm32f4.ld +++ b/core/embed/bootloader/memory_stm32f4.ld @@ -67,6 +67,8 @@ SECTIONS { .buf : ALIGN(4) { *(.buf*); . = ALIGN(4); + *(.no_dma_buffers*); + . = ALIGN(4); } >SRAM .boot_args : ALIGN(8) { diff --git a/core/embed/bootloader/memory_stm32u58.ld b/core/embed/bootloader/memory_stm32u58.ld index 059b4ca2d8..0812d1925c 100644 --- a/core/embed/bootloader/memory_stm32u58.ld +++ b/core/embed/bootloader/memory_stm32u58.ld @@ -78,6 +78,8 @@ SECTIONS { .buf : ALIGN(4) { *(.buf*); . = ALIGN(4); + *(.no_dma_buffers*); + . = ALIGN(4); } >SRAM1 .stack : ALIGN(8) { diff --git a/core/embed/bootloader/memory_stm32u5a.ld b/core/embed/bootloader/memory_stm32u5a.ld index 9803e696d9..e34a7d53e1 100644 --- a/core/embed/bootloader/memory_stm32u5a.ld +++ b/core/embed/bootloader/memory_stm32u5a.ld @@ -52,7 +52,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); @@ -78,6 +78,8 @@ SECTIONS { .buf : ALIGN(4) { *(.buf*); . = ALIGN(4); + *(.no_dma_buffers*); + . = ALIGN(4); } >SRAM1 .stack : ALIGN(8) { diff --git a/core/embed/bootloader/messages.c b/core/embed/bootloader/messages.c index 5b36003a07..5006afb856 100644 --- a/core/embed/bootloader/messages.c +++ b/core/embed/bootloader/messages.c @@ -37,6 +37,7 @@ #include "bootui.h" #include "messages.h" #include "rust_ui.h" +#include "version_check.h" #include "memzero.h" #include "model.h" @@ -213,8 +214,9 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) { continue; } else { // error - error_shutdown("USB ERROR", - "Error reading from USB. Try different USB cable."); + error_shutdown_ex("USB ERROR", + "Error reading from USB. Try different USB cable.", + NULL); } } return; // success @@ -471,6 +473,10 @@ static void detect_installation(const vendor_header *current_vhdr, *is_new = sectrue; return; } + if (sectrue != check_firmware_min_version(current_hdr->monotonic)) { + *is_new = sectrue; + return; + } if (sectrue != check_image_header_sig(current_hdr, current_vhdr->vsig_m, current_vhdr->vsig_n, current_vhdr->vpub)) { @@ -527,6 +533,14 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, return UPLOAD_ERR_INVALID_VENDOR_HEADER; } + if (sectrue != check_vendor_header_model(&vhdr)) { + MSG_SEND_INIT(Failure); + MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); + MSG_SEND_ASSIGN_STRING(message, "Wrong model"); + MSG_SEND(Failure); + return UPLOAD_ERR_INVALID_VENDOR_HEADER_MODEL; + } + if (sectrue != check_vendor_header_keys(&vhdr)) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); @@ -565,8 +579,31 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, return UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG; } + if (sectrue != check_firmware_min_version(received_hdr->monotonic)) { + MSG_SEND_INIT(Failure); + MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); + MSG_SEND_ASSIGN_STRING(message, "Cannot downgrade to this version"); + MSG_SEND(Failure); + return UPLOAD_ERR_INVALID_IMAGE_HEADER_VERSION; + } + memcpy(&hdr, received_hdr, sizeof(hdr)); + size_t headers_end = IMAGE_HEADER_SIZE + vhdr.hdrlen; + size_t tmp_headers_offset = + IMAGE_CODE_ALIGN(IMAGE_HEADER_SIZE + vhdr.hdrlen); + + // check padding between headers and the code + for (size_t i = headers_end; i < tmp_headers_offset; i++) { + if (CHUNK_BUFFER_PTR[i] != 0) { + MSG_SEND_INIT(Failure); + MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); + MSG_SEND_ASSIGN_STRING(message, "Invalid chunk padding"); + MSG_SEND(Failure); + return UPLOAD_ERR_INVALID_CHUNK_PADDING; + } + } + vendor_header current_vhdr; secbool is_new = secfalse; @@ -626,7 +663,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, return UPLOAD_ERR_NOT_FIRMWARE_UPGRADE; } - if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) { + if ((vhdr.vtrust & VTRUST_NO_WARNING) != VTRUST_NO_WARNING) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Not a full-trust image"); @@ -638,9 +675,9 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, is_ilu = sectrue; } -#if defined USE_OPTIGA && !defined STM32U5 - if (sectrue != secret_wiped() && - ((vhdr.vtrust & VTRUST_SECRET) != VTRUST_SECRET_ALLOW)) { +#if defined USE_OPTIGA + if (secfalse != secret_optiga_present() && + ((vhdr.vtrust & VTRUST_SECRET_MASK) != VTRUST_SECRET_ALLOW)) { MSG_SEND_INIT(Failure); MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Install restricted"); @@ -650,13 +687,20 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, #endif uint32_t response = INPUT_CANCEL; - if (sectrue == is_new || sectrue == is_ilu) { + if (((vhdr.vtrust & VTRUST_NO_WARNING) == VTRUST_NO_WARNING) && + (sectrue == is_new || sectrue == is_ilu)) { // new installation or interaction less updated - auto confirm + // only allowed for full-trust images response = INPUT_CONFIRM; } else { - int version_cmp = version_compare(hdr.version, current_hdr->version); - response = ui_screen_install_confirm(&vhdr, &hdr, should_keep_seed, - is_newvendor, version_cmp); + if (sectrue != is_new) { + int version_cmp = version_compare(hdr.version, current_hdr->version); + response = ui_screen_install_confirm( + &vhdr, &hdr, should_keep_seed, is_newvendor, is_new, version_cmp); + } else { + response = ui_screen_install_confirm(&vhdr, &hdr, sectrue, + is_newvendor, is_new, 0); + } } if (INPUT_CANCEL == response) { @@ -675,7 +719,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, NULL); } - headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen; + headers_offset = IMAGE_CODE_ALIGN(IMAGE_HEADER_SIZE + vhdr.hdrlen); read_offset = IMAGE_INIT_CHUNK_SIZE; // request the rest of the first chunk @@ -837,10 +881,10 @@ void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { MSG_SEND(Failure); } -#if defined USE_OPTIGA && !defined STM32U5 +#if defined USE_OPTIGA void process_msg_UnlockBootloader(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) { - secret_erase(); + secret_optiga_erase(); MSG_SEND_INIT(Success); MSG_SEND(Success); } diff --git a/core/embed/bootloader/messages.h b/core/embed/bootloader/messages.h index 1b69508634..ad8e3f4211 100644 --- a/core/embed/bootloader/messages.h +++ b/core/embed/bootloader/messages.h @@ -35,9 +35,11 @@ enum { UPLOAD_ERR_INVALID_CHUNK_SIZE = -1, UPLOAD_ERR_INVALID_VENDOR_HEADER = -2, UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG = -3, + UPLOAD_ERR_INVALID_VENDOR_HEADER_MODEL = -15, UPLOAD_ERR_INVALID_IMAGE_HEADER = -4, UPLOAD_ERR_INVALID_IMAGE_MODEL = -5, UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG = -6, + UPLOAD_ERR_INVALID_IMAGE_HEADER_VERSION = -16, UPLOAD_ERR_USER_ABORT = -7, UPLOAD_ERR_FIRMWARE_TOO_BIG = -8, UPLOAD_ERR_INVALID_CHUNK_HASH = -9, @@ -45,6 +47,7 @@ enum { UPLOAD_ERR_FIRMWARE_MISMATCH = -11, UPLOAD_ERR_NOT_FIRMWARE_UPGRADE = -12, UPLOAD_ERR_NOT_FULLTRUST_IMAGE = -13, + UPLOAD_ERR_INVALID_CHUNK_PADDING = -14, }; enum { diff --git a/core/embed/bootloader/protob/messages.pb.h b/core/embed/bootloader/protob/messages.pb.h index c623b94cf2..347bad7953 100644 --- a/core/embed/bootloader/protob/messages.pb.h +++ b/core/embed/bootloader/protob/messages.pb.h @@ -328,7 +328,7 @@ extern const pb_msgdesc_t UnlockBootloader_msg; /* Maximum encoded size of messages (where known) */ /* FirmwareUpload_size depends on runtime parameters */ #define ButtonAck_size 0 -#define ButtonRequest_size 2 +#define ButtonRequest_size 8 #define Failure_size 260 #define Features_size 497 #define FirmwareErase_size 6 diff --git a/core/embed/bootloader/version.h b/core/embed/bootloader/version.h index bc84518ec8..9d26d7379c 100644 --- a/core/embed/bootloader/version.h +++ b/core/embed/bootloader/version.h @@ -1,6 +1,10 @@ +#pragma once + +#include "model_version.h" + #define VERSION_MAJOR 2 #define VERSION_MINOR 1 -#define VERSION_PATCH 6 +#define VERSION_PATCH 8 #define VERSION_BUILD 0 #define VERSION_UINT32 \ (VERSION_MAJOR | (VERSION_MINOR << 8) | (VERSION_PATCH << 16) | \ @@ -10,9 +14,3 @@ #define FIX_VERSION_MINOR 0 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 - -#ifdef TREZOR_MODEL_R -#define VERSION_MONOTONIC 2 -#else -#define VERSION_MONOTONIC 1 -#endif diff --git a/core/embed/bootloader/version_check.c b/core/embed/bootloader/version_check.c new file mode 100644 index 0000000000..ae7d225154 --- /dev/null +++ b/core/embed/bootloader/version_check.c @@ -0,0 +1,48 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "version_check.h" + +#include "error_handling.h" +#include "model_version.h" +#include "monoctr.h" + +void ensure_bootloader_min_version(void) { + monoctr_write(MONOCTR_BOOTLOADER_VERSION, BOOTLOADER_MONOTONIC_VERSION); + uint8_t val = 0; + ensure(monoctr_read(MONOCTR_BOOTLOADER_VERSION, &val), NULL); + ensure(sectrue * (val == BOOTLOADER_MONOTONIC_VERSION), + "Bootloader downgrade protection"); +} + +secbool check_firmware_min_version(uint8_t check_version) { + uint8_t min_version = 0; + ensure(monoctr_read(MONOCTR_FIRMWARE_VERSION, &min_version), "monoctr read"); + + return (check_version >= min_version) * sectrue; +} + +void ensure_firmware_min_version(uint8_t version) { + monoctr_write(MONOCTR_FIRMWARE_VERSION, version); + uint8_t val = 0; + ensure(monoctr_read(MONOCTR_FIRMWARE_VERSION, &val), NULL); + ensure(sectrue * (val == version), "Firmware downgrade protection"); +} diff --git a/core/embed/bootloader/version_check.h b/core/embed/bootloader/version_check.h new file mode 100644 index 0000000000..a7011808b5 --- /dev/null +++ b/core/embed/bootloader/version_check.h @@ -0,0 +1,40 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include +#include "secbool.h" + +// Protection against bootloader downgrade + +// Ensures bootloader version is stored in monotonic counter +// If the version cannot be written, the function will shutdown the device +void ensure_bootloader_min_version(void); + +// Protection against firmware downgrade + +// This functions checks if the firmware version is at least the minimum +// required version, returns sectrue if check_version is higher or equal to the +// stored version +secbool check_firmware_min_version(uint8_t check_version); + +// Ensures firmware version is stored in monotonic counter +// If the version cannot be written, the function will shutdown the device +void ensure_firmware_min_version(uint8_t version); diff --git a/core/embed/bootloader_ci/bootui.c b/core/embed/bootloader_ci/bootui.c index e98326536d..7b6a4e288e 100644 --- a/core/embed/bootloader_ci/bootui.c +++ b/core/embed/bootloader_ci/bootui.c @@ -21,6 +21,7 @@ #include "bootui.h" #include "display.h" +#include "display_draw.h" #include "display_utils.h" #include "icon_done.h" #include "icon_fail.h" diff --git a/core/embed/bootloader_ci/header.S b/core/embed/bootloader_ci/header.S index bb386ef7fd..8945f4cd29 100644 --- a/core/embed/bootloader_ci/header.S +++ b/core/embed/bootloader_ci/header.S @@ -26,7 +26,7 @@ g_header: .byte FIX_VERSION_BUILD // fix_vbuild .word HW_MODEL // type of the designated hardware .byte HW_REVISION // revision of the designated hardware - .byte VERSION_MONOTONIC // monotonic version + .byte BOOTLOADER_MONOTONIC_VERSION // monotonic version of the binary . = . + 2 // reserved . = . + 512 // hash1 ... hash16 . = . + 415 // reserved diff --git a/core/embed/bootloader_ci/main.c b/core/embed/bootloader_ci/main.c index 40c56d58a9..e58a1a95b2 100644 --- a/core/embed/bootloader_ci/main.c +++ b/core/embed/bootloader_ci/main.c @@ -22,6 +22,7 @@ #include "common.h" #include "display.h" +#include "display_draw.h" #include "flash.h" #include "flash_otp.h" #include "image.h" @@ -56,8 +57,8 @@ static void usb_init_all(secbool usb21_landing) { .vendor_id = 0x1209, .product_id = 0x53C0, .release_num = 0x0200, - .manufacturer = "SatoshiLabs", - .product = "TREZOR", + .manufacturer = MODEL_USB_MANUFACTURER, + .product = MODEL_USB_PRODUCT, .serial_number = "000000000000000000000000", .interface = "TREZOR Interface", .usb21_enabled = sectrue, @@ -68,8 +69,8 @@ static void usb_init_all(secbool usb21_landing) { static const usb_webusb_info_t webusb_info = { .iface_num = USB_IFACE_NUM, - .ep_in = USB_EP_DIR_IN | 0x01, - .ep_out = USB_EP_DIR_OUT | 0x01, + .ep_in = 0x01, + .ep_out = 0x01, .subclass = 0, .protocol = 0, .max_packet_len = sizeof(rx_buffer), @@ -77,11 +78,11 @@ static void usb_init_all(secbool usb21_landing) { .polling_interval = 1, }; - usb_init(&dev_info); + ensure(usb_init(&dev_info), NULL); ensure(usb_webusb_add(&webusb_info), NULL); - usb_start(); + ensure(usb_start(), NULL); } static secbool bootloader_usb_loop(const vendor_header *const vhdr, @@ -116,12 +117,10 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, r = process_msg_WipeDevice(USB_IFACE_NUM, msg_size, buf); if (r < 0) { // error ui_screen_fail(); - usb_stop(); usb_deinit(); return secfalse; // shutdown } else { // success ui_screen_done(0, sectrue); - usb_stop(); usb_deinit(); return secfalse; // shutdown } @@ -133,7 +132,6 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf); if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort ui_screen_fail(); - usb_stop(); usb_deinit(); return secfalse; // shutdown } else if (r == 0) { // last chunk received @@ -145,7 +143,6 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr, hal_delay(1000); ui_screen_done(1, secfalse); hal_delay(1000); - usb_stop(); usb_deinit(); return sectrue; // jump to firmware } @@ -209,7 +206,6 @@ int main(void) { random_delays_init(); #ifdef USE_TOUCH touch_init(); - touch_power_on(); #endif #ifdef USE_HASH_PROCESSOR @@ -297,11 +293,8 @@ int main(void) { // do not check any trust flags on header, proceed - // mpu_config_firmware(); - // jump_to_unprivileged(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); - mpu_config_off(); - jump_to(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE); + jump_to(IMAGE_CODE_ALIGN(FIRMWARE_START + vhdr.hdrlen + IMAGE_HEADER_SIZE)); return 0; } diff --git a/core/embed/bootloader_ci/memory_stm32f4.ld b/core/embed/bootloader_ci/memory_stm32f4.ld index d66d8bfc38..42eb1cd20c 100644 --- a/core/embed/bootloader_ci/memory_stm32f4.ld +++ b/core/embed/bootloader_ci/memory_stm32f4.ld @@ -73,4 +73,10 @@ SECTIONS { *(.boot_args*); . = ALIGN(8); } >BOOT_ARGS + + .data_ccm : ALIGN(4) { + *(.no_dma_buffers*); + . = ALIGN(4); + } >CCMRAM + } diff --git a/core/embed/bootloader_ci/memory_stm32u5a.ld b/core/embed/bootloader_ci/memory_stm32u5a.ld index 9803e696d9..accf765861 100644 --- a/core/embed/bootloader_ci/memory_stm32u5a.ld +++ b/core/embed/bootloader_ci/memory_stm32u5a.ld @@ -52,7 +52,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/bootloader_ci/messages.c b/core/embed/bootloader_ci/messages.c index 15c5ce22c5..ee177017a1 100644 --- a/core/embed/bootloader_ci/messages.c +++ b/core/embed/bootloader_ci/messages.c @@ -200,8 +200,9 @@ static void _usb_webusb_read_retry(uint8_t iface_num, uint8_t *buf) { // only timeout => let's try again } else { // error - error_shutdown("USB ERROR", - "Error reading from USB. Try different USB cable."); + error_shutdown_ex("USB ERROR", + "Error reading from USB. Try different USB cable.", + NULL); } } return; // success @@ -557,7 +558,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, // no user confirmations, go directly to upload - headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen; + headers_offset = IMAGE_CODE_ALIGN(IMAGE_HEADER_SIZE + vhdr.hdrlen); read_offset = IMAGE_INIT_CHUNK_SIZE; // request the rest of the first chunk diff --git a/core/embed/bootloader_ci/version.h b/core/embed/bootloader_ci/version.h index 05d8755e76..d1193c9435 100644 --- a/core/embed/bootloader_ci/version.h +++ b/core/embed/bootloader_ci/version.h @@ -1,3 +1,7 @@ +#pragma once + +#include "model_version.h" + #define VERSION_MAJOR 2 #define VERSION_MINOR 0 #define VERSION_PATCH 4 @@ -10,5 +14,3 @@ #define FIX_VERSION_MINOR 0 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 - -#define VERSION_MONOTONIC 1 diff --git a/core/embed/extmod/modtrezorconfig/norcow_config.h b/core/embed/extmod/modtrezorconfig/norcow_config.h index 32992e0556..f9233cb7e2 100644 --- a/core/embed/extmod/modtrezorconfig/norcow_config.h +++ b/core/embed/extmod/modtrezorconfig/norcow_config.h @@ -30,6 +30,6 @@ /* * Current storage version. */ -#define NORCOW_VERSION ((uint32_t)0x00000004) +#define NORCOW_VERSION ((uint32_t)0x00000005) #endif diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-aesgcm.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-aesgcm.h index c29de6d734..b7edf784b8 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-aesgcm.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-aesgcm.h @@ -110,6 +110,28 @@ STATIC mp_obj_t mod_trezorcrypto_AesGcm_encrypt(mp_obj_t self, mp_obj_t data) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AesGcm_encrypt_obj, mod_trezorcrypto_AesGcm_encrypt); +/// def encrypt_in_place(self, data: bytearray | memoryview) -> int: +/// """ +/// Encrypt data chunk in place. Returns the length of the encrypted data. +/// """ +STATIC mp_obj_t mod_trezorcrypto_AesGcm_encrypt_in_place(mp_obj_t self, + mp_obj_t data) { + mp_obj_AesGcm_t *o = MP_OBJ_TO_PTR(self); + if (o->state != STATE_INIT && o->state != STATE_ENCRYPTING) { + mp_raise_msg(&mp_type_RuntimeError, "Invalid state."); + } + o->state = STATE_ENCRYPTING; + mp_buffer_info_t in = {0}; + mp_get_buffer_raise(data, &in, MP_BUFFER_READ | MP_BUFFER_WRITE); + if (gcm_encrypt((unsigned char *)in.buf, in.len, &(o->ctx)) != RETURN_GOOD) { + o->state = STATE_FAILED; + mp_raise_type(&mp_type_RuntimeError); + } + return mp_obj_new_int(in.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AesGcm_encrypt_in_place_obj, + mod_trezorcrypto_AesGcm_encrypt_in_place); + /// def decrypt(self, data: bytes) -> bytes: /// """ /// Decrypt data chunk. @@ -135,6 +157,28 @@ STATIC mp_obj_t mod_trezorcrypto_AesGcm_decrypt(mp_obj_t self, mp_obj_t data) { STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AesGcm_decrypt_obj, mod_trezorcrypto_AesGcm_decrypt); +/// def decrypt_in_place(self, data: bytearray | memoryview) -> int: +/// """ +/// Decrypt data chunk in place. Returns the length of the decrypted data. +/// """ +STATIC mp_obj_t mod_trezorcrypto_AesGcm_decrypt_in_place(mp_obj_t self, + mp_obj_t data) { + mp_obj_AesGcm_t *o = MP_OBJ_TO_PTR(self); + if (o->state != STATE_INIT && o->state != STATE_DECRYPTING) { + mp_raise_msg(&mp_type_RuntimeError, "Invalid state."); + } + o->state = STATE_DECRYPTING; + mp_buffer_info_t in = {0}; + mp_get_buffer_raise(data, &in, MP_BUFFER_READ | MP_BUFFER_WRITE); + if (gcm_decrypt((unsigned char *)in.buf, in.len, &(o->ctx)) != RETURN_GOOD) { + o->state = STATE_FAILED; + mp_raise_type(&mp_type_RuntimeError); + } + return mp_obj_new_int(in.len); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_AesGcm_decrypt_in_place_obj, + mod_trezorcrypto_AesGcm_decrypt_in_place); + /// def auth(self, data: bytes) -> None: /// """ /// Include authenticated data chunk in the GCM authentication tag. This can @@ -194,8 +238,12 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_AesGcm_locals_dict_table[] = { MP_ROM_PTR(&mod_trezorcrypto_AesGcm_reset_obj)}, {MP_ROM_QSTR(MP_QSTR_encrypt), MP_ROM_PTR(&mod_trezorcrypto_AesGcm_encrypt_obj)}, + {MP_ROM_QSTR(MP_QSTR_encrypt_in_place), + MP_ROM_PTR(&mod_trezorcrypto_AesGcm_encrypt_in_place_obj)}, {MP_ROM_QSTR(MP_QSTR_decrypt), MP_ROM_PTR(&mod_trezorcrypto_AesGcm_decrypt_obj)}, + {MP_ROM_QSTR(MP_QSTR_decrypt_in_place), + MP_ROM_PTR(&mod_trezorcrypto_AesGcm_decrypt_in_place_obj)}, {MP_ROM_QSTR(MP_QSTR_auth), MP_ROM_PTR(&mod_trezorcrypto_AesGcm_auth_obj)}, {MP_ROM_QSTR(MP_QSTR_finish), MP_ROM_PTR(&mod_trezorcrypto_AesGcm_finish_obj)}, diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h index afae086504..ed0794b597 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-bip32.h @@ -131,8 +131,10 @@ STATIC mp_obj_t mod_trezorcrypto_HDNode_make_new(const mp_obj_type_t *type, } if (33 == public_key.len) { memcpy(o->hdnode.public_key, public_key.buf, 33); + o->hdnode.is_public_key_set = true; } else { memzero(o->hdnode.public_key, 33); + o->hdnode.is_public_key_set = false; } o->hdnode.curve = curve; diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-crc.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-crc.h index 2cf8d7b97b..ab0042eef3 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-crc.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-crc.h @@ -28,6 +28,14 @@ /// def crc32(data: bytes, crc: int = 0) -> int: /// """ /// Computes a CRC32 checksum of `data`. +/// +/// Args: +/// `data` (`bytes`): Input data. +/// `crc` (`int`, `optional`): Initial CRC value for chaining +/// computations over multiple data segments. Defaults to 0. +/// +/// Returns: +/// `int`: Computed CRC32 checksum. /// """ mp_obj_t mod_trezorcrypto_crc_crc32(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t bufinfo = {0}; diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h index 17fea3cbcc..fb3fa4c7c8 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ed25519.h @@ -34,10 +34,6 @@ STATIC mp_obj_t mod_trezorcrypto_ed25519_generate_secret() { vstr_t sk = {0}; vstr_init_len(&sk, 32); random_buffer((uint8_t *)sk.buf, sk.len); - // taken from https://cr.yp.to/ecdh.html - sk.buf[0] &= 248; - sk.buf[31] &= 127; - sk.buf[31] |= 64; return mp_obj_new_str_from_vstr(&mp_type_bytes, &sk); } STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_ed25519_generate_secret_obj, @@ -104,16 +100,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorcrypto_ed25519_sign_obj, 2, #if !BITCOIN_ONLY /// def sign_ext( -/// secret_key: bytes, secret_extension: bytes, message: bytes +/// secret_scalar: bytes, secret_extension: bytes, message: bytes /// ) -> bytes: /// """ -/// Uses secret key to produce the cardano signature of message. +/// Uses extended secret key to produce the cardano signature of message. /// """ -STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_key, +STATIC mp_obj_t mod_trezorcrypto_ed25519_sign_ext(mp_obj_t secret_scalar, mp_obj_t secret_extension, mp_obj_t message) { mp_buffer_info_t sk = {0}, skext = {0}, msg = {0}; - mp_get_buffer_raise(secret_key, &sk, MP_BUFFER_READ); + mp_get_buffer_raise(secret_scalar, &sk, MP_BUFFER_READ); mp_get_buffer_raise(secret_extension, &skext, MP_BUFFER_READ); mp_get_buffer_raise(message, &msg, MP_BUFFER_READ); if (sk.len != 32) { diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-elligator2.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-elligator2.h new file mode 100644 index 0000000000..8bbfd7910d --- /dev/null +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-elligator2.h @@ -0,0 +1,64 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "py/objstr.h" + +#include "embed/extmod/trezorobj.h" + +#include "elligator2.h" + +/// package: trezorcrypto.elligator2 + +/// def map_to_curve25519(input: bytes) -> bytes: +/// """ +/// Maps a 32-byte input to a curve25519 point. +/// """ +mp_obj_t mod_trezorcrypto_elligator2_map_to_curve25519(mp_obj_t input) { + mp_buffer_info_t input_buffer_info = {0}; + mp_get_buffer_raise(input, &input_buffer_info, MP_BUFFER_READ); + if (input_buffer_info.len != 32) { + mp_raise_ValueError("Invalid input length"); + } + + vstr_t output_vstr = {0}; + vstr_init_len(&output_vstr, 32); + int res = map_to_curve_elligator2_curve25519(input_buffer_info.buf, + (uint8_t *)output_vstr.buf); + if (res != true) { + mp_raise_ValueError(NULL); + } + + return mp_obj_new_str_from_vstr(&mp_type_bytes, &output_vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1( + mod_trezorcrypto_elligator2_map_to_curve25519_obj, + mod_trezorcrypto_elligator2_map_to_curve25519); + +STATIC const mp_rom_map_elem_t mod_trezorcrypto_elligator2_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_elligator2)}, + {MP_ROM_QSTR(MP_QSTR_map_to_curve25519), + MP_ROM_PTR(&mod_trezorcrypto_elligator2_map_to_curve25519_obj)}, +}; +STATIC MP_DEFINE_CONST_DICT(mod_trezorcrypto_elligator2_globals, + mod_trezorcrypto_elligator2_globals_table); + +STATIC const mp_obj_module_t mod_trezorcrypto_elligator2_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&mod_trezorcrypto_elligator2_globals, +}; diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-monero.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-monero.h index 0518294657..a28d1bd523 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-monero.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-monero.h @@ -140,7 +140,7 @@ STATIC void mp_unpack_scalar(bignum256modm r, const mp_obj_t arg, /// """ /// EC point on ED25519 /// """ -/// + /// def __init__(self, x: Point | bytes | None = None): /// """ /// Constructor @@ -179,13 +179,12 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_monero_ge25519___del___obj, /// """ /// EC scalar on SC25519 /// """ -/// + /// def __init__(self, x: Scalar | bytes | int | None = None): /// """ /// Constructor /// """ -/// -/// + STATIC mp_obj_t mod_trezorcrypto_monero_bignum256modm_make_new( const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -223,28 +222,27 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1( /// """ /// XMR hasher /// """ -/// + /// def __init__(self, x: bytes | None = None): /// """ /// Constructor /// """ -/// + /// def update(self, buffer: bytes) -> None: /// """ /// Update hasher /// """ -/// + /// def digest(self) -> bytes: /// """ /// Computes digest /// """ -/// + /// def copy(self) -> Hasher: /// """ /// Creates copy of the hasher, preserving the state /// """ -/// -/// + STATIC mp_obj_t mod_trezorcrypto_monero_hasher_make_new( const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h index 08a77d8a4e..040de99622 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-optiga.h @@ -90,11 +90,12 @@ STATIC mp_obj_t mod_trezorcrypto_optiga_sign(mp_obj_t key_index, vstr_t sig = {0}; vstr_init_len(&sig, MAX_DER_SIGNATURE_SIZE); size_t sig_size = 0; - int ret = optiga_sign(idx, (const uint8_t *)dig.buf, dig.len, - ((uint8_t *)sig.buf), sig.alloc, &sig_size); - if (ret != 0) { + optiga_sign_result ret = + optiga_sign(idx, (const uint8_t *)dig.buf, dig.len, ((uint8_t *)sig.buf), + sig.alloc, &sig_size); + if (ret != OPTIGA_SIGN_SUCCESS) { vstr_clear(&sig); - if (ret == OPTIGA_ERR_ACCESS_COND_NOT_SAT) { + if (ret == OPTIGA_SIGN_INACCESSIBLE) { mp_raise_msg(&mp_type_SigningInaccessible, "Signing inaccessible."); } else { mp_raise_msg(&mp_type_OptigaError, "Signing failed."); @@ -104,10 +105,36 @@ STATIC mp_obj_t mod_trezorcrypto_optiga_sign(mp_obj_t key_index, sig.len = sig_size; return mp_obj_new_str_from_vstr(&mp_type_bytes, &sig); } - STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorcrypto_optiga_sign_obj, mod_trezorcrypto_optiga_sign); +/// def get_sec() -> int | None: +/// """ +/// Returns the value of Optiga's security event counter. +/// """ +STATIC mp_obj_t mod_trezorcrypto_optiga_get_sec() { + uint8_t sec = 0; + if (optiga_read_sec(&sec)) { + return mp_obj_new_int_from_uint(sec); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_optiga_get_sec_obj, + mod_trezorcrypto_optiga_get_sec); + +#if PYOPT == 0 +/// def set_sec_max() -> None: +/// """ +/// Set Optiga's security event counter to maximum. +/// """ +STATIC mp_obj_t mod_trezorcrypto_optiga_set_sec_max() { + optiga_set_sec_max(); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorcrypto_optiga_set_sec_max_obj, + mod_trezorcrypto_optiga_set_sec_max); +#endif + /// DEVICE_CERT_INDEX: int /// DEVICE_ECC_KEY_INDEX: int @@ -116,6 +143,12 @@ STATIC const mp_rom_map_elem_t mod_trezorcrypto_optiga_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_get_certificate), MP_ROM_PTR(&mod_trezorcrypto_optiga_get_certificate_obj)}, {MP_ROM_QSTR(MP_QSTR_sign), MP_ROM_PTR(&mod_trezorcrypto_optiga_sign_obj)}, + {MP_ROM_QSTR(MP_QSTR_get_sec), + MP_ROM_PTR(&mod_trezorcrypto_optiga_get_sec_obj)}, +#if PYOPT == 0 + {MP_ROM_QSTR(MP_QSTR_set_sec_max), + MP_ROM_PTR(&mod_trezorcrypto_optiga_set_sec_max_obj)}, +#endif {MP_ROM_QSTR(MP_QSTR_DEVICE_CERT_INDEX), MP_ROM_INT(OPTIGA_DEVICE_CERT_INDEX)}, {MP_ROM_QSTR(MP_QSTR_DEVICE_ECC_KEY_INDEX), diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h index 7a9f258222..6a05382deb 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto-ripemd160.h @@ -32,7 +32,7 @@ /// digest_size: int typedef struct _mp_obj_Ripemd160_t { mp_obj_base_t base; - RIPEMD160_CTX ctx; + ripemd160_state ctx; } mp_obj_Ripemd160_t; STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_obj_t data); @@ -47,7 +47,7 @@ STATIC mp_obj_t mod_trezorcrypto_Ripemd160_make_new(const mp_obj_type_t *type, mp_arg_check_num(n_args, n_kw, 0, 1, false); mp_obj_Ripemd160_t *o = m_new_obj_with_finaliser(mp_obj_Ripemd160_t); o->base.type = type; - ripemd160_Init(&(o->ctx)); + ripemd160_init(&(o->ctx)); // constructor called with bytes/str as first parameter if (n_args == 1) { mod_trezorcrypto_Ripemd160_update(MP_OBJ_FROM_PTR(o), args[0]); @@ -65,7 +65,7 @@ STATIC mp_obj_t mod_trezorcrypto_Ripemd160_update(mp_obj_t self, mp_buffer_info_t msg = {0}; mp_get_buffer_raise(data, &msg, MP_BUFFER_READ); if (msg.len > 0) { - ripemd160_Update(&(o->ctx), msg.buf, msg.len); + ripemd160_process(&(o->ctx), msg.buf, msg.len); } return mp_const_none; } @@ -80,10 +80,10 @@ STATIC mp_obj_t mod_trezorcrypto_Ripemd160_digest(mp_obj_t self) { mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); vstr_t hash = {0}; vstr_init_len(&hash, RIPEMD160_DIGEST_LENGTH); - RIPEMD160_CTX ctx = {0}; - memcpy(&ctx, &(o->ctx), sizeof(RIPEMD160_CTX)); - ripemd160_Final(&ctx, (uint8_t *)hash.buf); - memzero(&ctx, sizeof(RIPEMD160_CTX)); + ripemd160_state ctx = {0}; + memcpy(&ctx, &(o->ctx), sizeof(ripemd160_state)); + ripemd160_done(&ctx, (uint8_t *)hash.buf); + memzero(&ctx, sizeof(ripemd160_state)); return mp_obj_new_str_from_vstr(&mp_type_bytes, &hash); } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160_digest_obj, @@ -91,7 +91,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160_digest_obj, STATIC mp_obj_t mod_trezorcrypto_Ripemd160___del__(mp_obj_t self) { mp_obj_Ripemd160_t *o = MP_OBJ_TO_PTR(self); - memzero(&(o->ctx), sizeof(RIPEMD160_CTX)); + memzero(&(o->ctx), sizeof(ripemd160_state)); return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorcrypto_Ripemd160___del___obj, diff --git a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c index ebd9ce34a0..13282bd93a 100644 --- a/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c +++ b/core/embed/extmod/modtrezorcrypto/modtrezorcrypto.c @@ -55,6 +55,9 @@ static void wrapped_ui_wait_callback(uint32_t current, uint32_t total) { #include "modtrezorcrypto-crc.h" #include "modtrezorcrypto-curve25519.h" #include "modtrezorcrypto-ed25519.h" +#if USE_THP +#include "modtrezorcrypto-elligator2.h" +#endif #include "modtrezorcrypto-groestl.h" #include "modtrezorcrypto-hmac.h" #include "modtrezorcrypto-nist256p1.h" @@ -102,6 +105,10 @@ STATIC const mp_rom_map_elem_t mp_module_trezorcrypto_globals_table[] = { MP_ROM_PTR(&mod_trezorcrypto_curve25519_module)}, {MP_ROM_QSTR(MP_QSTR_ed25519), MP_ROM_PTR(&mod_trezorcrypto_ed25519_module)}, +#if USE_THP + {MP_ROM_QSTR(MP_QSTR_elligator2), + MP_ROM_PTR(&mod_trezorcrypto_elligator2_module)}, +#endif #if !BITCOIN_ONLY {MP_ROM_QSTR(MP_QSTR_monero), MP_ROM_PTR(&mod_trezorcrypto_monero_module)}, #endif @@ -154,8 +161,7 @@ void secp256k1_default_illegal_callback_fn(const char *str, void *data) { void secp256k1_default_error_callback_fn(const char *str, void *data) { (void)data; - __fatal_error(NULL, str, __FILE__, __LINE__, __func__); - return; + error_shutdown(str); } #endif diff --git a/core/embed/extmod/modtrezorio/ff.c b/core/embed/extmod/modtrezorio/ff.c index b48b70b30e..ae62e0efc2 100644 --- a/core/embed/extmod/modtrezorio/ff.c +++ b/core/embed/extmod/modtrezorio/ff.c @@ -418,8 +418,6 @@ #define MKCVTBL(hd, cp) MERGE_2STR(hd, cp) - - /*-------------------------------------------------------------------------- Module Private Work Area @@ -3262,12 +3260,9 @@ FRESULT f_setlabel ( } - - - - - - +static inline int progress_section(int start, int size, int current, int first) { + return start + size - (current ? ((current * size) / first) : 0); +} #if !FF_FS_READONLY && FF_USE_MKFS @@ -3346,17 +3341,25 @@ FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ const MKFS_PARM* opt, /* Format options */ void* work, /* Pointer to working buffer (null: use len bytes of heap memory) */ - UINT len /* Size of working buffer [byte] */ + UINT len, /* Size of working buffer [byte] */ + void (*progress_callback)(uint32_t current /* 0-1000 */) /* Callback used to report progress (NULL: no progress reporting) */ ) { static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT volume (4Ks unit) */ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128Ks unit) */ static const MKFS_PARM defopt = {FM_ANY, 0, 0, 0, 0}; /* Default parameter */ + static const WORD p_initial = 0; + static const WORD p_fat_area_before = 10; + static const WORD p_fat_area_sz = 790; + static const WORD p_root_dir_before = p_fat_area_before + p_fat_area_sz; + static const WORD p_root_dir_sz = 100; + static const WORD p_final = 1000; + static const WORD p_num_calls = 10; /* Limit of number of calls to report progress in each loop */ BYTE fsopt = 0, fsty = 0, sys = 0, pdrv = 0, ipart = 0; BYTE *buf = NULL; BYTE *pte = NULL; WORD ss = 0; /* Sector size */ - DWORD sz_buf = 0, sz_blk = 0, n_clst = 0, pau = 0, nsect = 0, n = 0, vsn = 0; + DWORD sz_buf = 0, sz_blk = 0, n_clst = 0, pau = 0, nsect = 0, nsect0 = 0, n = 0, vsn = 0; LBA_t sz_vol, b_vol, b_fat, b_data; /* Size of volume, Base LBA of volume, fat, data */ LBA_t sect = 0, lba[2] = {0}; DWORD sz_rsv, sz_fat, sz_dir, sz_au; /* Size of reserved, fat, dir, data, cluster */ @@ -3364,7 +3367,11 @@ FRESULT f_mkfs ( int vol = 0; DSTATUS ds = 0; FRESULT res = 0; + DWORD iter, progress_steps; + if (progress_callback) { + progress_callback(p_initial); + } /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ @@ -3570,6 +3577,10 @@ FRESULT f_mkfs ( disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */ } + if (progress_callback) { + progress_callback(p_fat_area_before); + } + /* Initialize FAT area */ memset(buf, 0, sz_buf * ss); sect = b_fat; /* FAT start sector */ @@ -3581,24 +3592,46 @@ FRESULT f_mkfs ( } else { st_dword(buf + 0, (fsty == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* FAT[0] and FAT[1] */ } - nsect = sz_fat; /* Number of FAT sectors */ + nsect0 = nsect = sz_fat; /* Number of FAT sectors */ + progress_steps = nsect / sz_buf / p_num_calls; + iter = 0; do { /* Fill FAT sectors */ n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); memset(buf, 0, ss); /* Rest of FAT all are cleared */ sect += n; nsect -= n; + iter++; + + if (progress_callback && progress_steps && iter % progress_steps == 0) { + progress_callback(progress_section(p_fat_area_before, p_fat_area_sz, nsect, nsect0)); + } } while (nsect); } + if (progress_callback) { + progress_callback(p_root_dir_before); + } + /* Initialize root directory (fill with zero) */ - nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + nsect0 = nsect = (fsty == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */ + progress_steps = nsect / sz_buf / p_num_calls; + iter = 0; do { n = (nsect > sz_buf) ? sz_buf : nsect; if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); sect += n; nsect -= n; + iter++; + + if (progress_callback && progress_steps && iter % progress_steps == 0) { + progress_callback(progress_section(p_root_dir_before, p_root_dir_sz, nsect, nsect0)); + } } while (nsect); } + if (progress_callback) { + progress_callback(p_root_dir_before + p_root_dir_sz); + } + /* A FAT volume has been created here */ /* Determine system ID in the MBR partition table */ @@ -3632,6 +3665,10 @@ FRESULT f_mkfs ( if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) LEAVE_MKFS(FR_DISK_ERR); + if (progress_callback) { + progress_callback(p_final); + } + LEAVE_MKFS(FR_OK); } diff --git a/core/embed/extmod/modtrezorio/ff.h b/core/embed/extmod/modtrezorio/ff.h index 88fb318750..c26244be58 100644 --- a/core/embed/extmod/modtrezorio/ff.h +++ b/core/embed/extmod/modtrezorio/ff.h @@ -330,7 +330,7 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */ FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */ FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */ FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */ -FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len); /* Create a FAT volume */ +FRESULT f_mkfs (const TCHAR* path, const MKFS_PARM* opt, void* work, UINT len, void (*progress_callback)(uint32_t current)); /* Create a FAT volume */ FRESULT f_fdisk (BYTE pdrv, const LBA_t ptbl[], void* work); /* Divide a physical drive into some partitions */ FRESULT f_setcp (WORD cp); /* Set current code page */ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */ diff --git a/core/embed/extmod/modtrezorio/modtrezorio-fatfs.h b/core/embed/extmod/modtrezorio/modtrezorio-fatfs.h index 1cf7f253f3..689f881234 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-fatfs.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-fatfs.h @@ -528,24 +528,43 @@ STATIC mp_obj_t mod_trezorio_fatfs_is_mounted() { STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_is_mounted_obj, mod_trezorio_fatfs_is_mounted); -/// def mkfs() -> None: +STATIC mp_obj_t ui_wait_callback = mp_const_none; + +STATIC void wrapped_ui_wait_callback(uint32_t current) { + if (mp_obj_is_callable(ui_wait_callback)) { + mp_call_function_1_protected(ui_wait_callback, mp_obj_new_int(current)); + } +} + +/// def mkfs(callback: Callable[[int], None] | None = None) -> None: /// """ /// Create a FAT volume on the SD card, /// """ -STATIC mp_obj_t mod_trezorio_fatfs_mkfs() { +STATIC mp_obj_t mod_trezorio_fatfs_mkfs(size_t n_args, const mp_obj_t *args) { if (_fatfs_instance_is_mounted()) { FATFS_RAISE(FatFSError, FR_LOCKED); } MKFS_PARM params = {FM_FAT32, 0, 0, 0, 0}; uint8_t working_buf[FF_MAX_SS] = {0}; - FRESULT res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf)); + FRESULT res; + if (n_args == 1) { + // format with a progress callback + ui_wait_callback = args[0]; + res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf), + wrapped_ui_wait_callback); + ui_wait_callback = mp_const_none; + } else { + // format without a progress callback + res = f_mkfs("", ¶ms, working_buf, sizeof(working_buf), NULL); + } + if (res != FR_OK) { FATFS_RAISE(FatFSError, res); } return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorio_fatfs_mkfs_obj, - mod_trezorio_fatfs_mkfs); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorio_fatfs_mkfs_obj, 0, 1, + mod_trezorio_fatfs_mkfs); /// def setlabel(label: str) -> None: /// """ diff --git a/core/embed/extmod/modtrezorio/modtrezorio-haptic.h b/core/embed/extmod/modtrezorio/modtrezorio-haptic.h new file mode 100644 index 0000000000..9462b82614 --- /dev/null +++ b/core/embed/extmod/modtrezorio/modtrezorio-haptic.h @@ -0,0 +1,47 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "haptic.h" + +/// package: trezorio.haptic + +/// def haptic_set_enabled(enable: bool) -> None: +/// """ +/// Enable/Disable the haptic feedback. +/// """ +STATIC mp_obj_t mod_trezorio_haptic_set_enabled(mp_obj_t enable) { + haptic_set_enabled(mp_obj_is_true(enable)); + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_haptic_set_enabled_obj, + mod_trezorio_haptic_set_enabled); + +STATIC const mp_rom_map_elem_t mod_trezorio_haptic_globals_table[] = { + {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_haptic)}, + {MP_ROM_QSTR(MP_QSTR_haptic_set_enabled), + MP_ROM_PTR(&mod_trezorio_haptic_set_enabled_obj)}, + +}; +STATIC MP_DEFINE_CONST_DICT(mod_trezorio_haptic_globals, + mod_trezorio_haptic_globals_table); + +STATIC const mp_obj_module_t mod_trezorio_haptic_module = { + .base = {&mp_type_module}, + .globals = (mp_obj_dict_t *)&mod_trezorio_haptic_globals, +}; diff --git a/core/embed/extmod/modtrezorio/modtrezorio-poll.h b/core/embed/extmod/modtrezorio/modtrezorio-poll.h index da5b122477..a5f1bc89c2 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-poll.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-poll.h @@ -31,17 +31,18 @@ #define POLL_WRITE (0x0100) extern bool usb_connected_previously; +extern uint32_t last_touch_sample_time; /// package: trezorio.__init__ /// def poll(ifaces: Iterable[int], list_ref: list, timeout_ms: int) -> bool: /// """ /// Wait until one of `ifaces` is ready to read or write (using masks -// `io.POLL_READ` and `io.POLL_WRITE`) and assign the result into +/// `io.POLL_READ` and `io.POLL_WRITE`) and assign the result into /// `list_ref`: /// -/// `list_ref[0]` - the interface number, including the mask -/// `list_ref[1]` - for touch event, tuple of: +/// - `list_ref[0]` - the interface number, including the mask +/// - `list_ref[1]` - for touch event, tuple of: /// (event_type, x_position, y_position) /// - for button event (T1), tuple of: /// (event type, button number) @@ -84,38 +85,44 @@ STATIC mp_obj_t mod_trezorio_poll(mp_obj_t ifaces, mp_obj_t list_ref, } #if defined USE_TOUCH else if (iface == TOUCH_IFACE) { - const uint32_t evt = touch_read(); + const uint32_t evt = touch_get_event(); if (evt) { - mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); - const uint32_t etype = (evt >> 24) & 0xFFU; // event type - const uint32_t ex = (evt >> 12) & 0xFFFU; // x position - const uint32_t ey = evt & 0xFFFU; // y position - uint32_t exr; // rotated x position - uint32_t eyr; // rotated y position - switch (display_orientation(-1)) { - case 90: - exr = ey; - eyr = DISPLAY_RESX - ex; - break; - case 180: - exr = DISPLAY_RESX - ex; - eyr = DISPLAY_RESY - ey; - break; - case 270: - exr = DISPLAY_RESY - ey; - eyr = ex; - break; - default: - exr = ex; - eyr = ey; - break; + // ignore TOUCH_MOVE events if they are too frequent + if ((evt & TOUCH_MOVE) == 0 || + (hal_ticks_ms() - last_touch_sample_time > 10)) { + last_touch_sample_time = hal_ticks_ms(); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL)); + const uint32_t etype = (evt >> 24) & 0xFFU; // event type + const uint32_t ex = (evt >> 12) & 0xFFFU; // x position + const uint32_t ey = evt & 0xFFFU; // y position + uint32_t exr; // rotated x position + uint32_t eyr; // rotated y position + switch (display_orientation(-1)) { + case 90: + exr = ey; + eyr = DISPLAY_RESX - ex; + break; + case 180: + exr = DISPLAY_RESX - ex; + eyr = DISPLAY_RESY - ey; + break; + case 270: + exr = DISPLAY_RESY - ey; + eyr = ex; + break; + default: + exr = ex; + eyr = ey; + break; + } + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(exr); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(eyr); + ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); + ret->items[1] = MP_OBJ_FROM_PTR(tuple); + return mp_const_true; } - tuple->items[0] = MP_OBJ_NEW_SMALL_INT(etype); - tuple->items[1] = MP_OBJ_NEW_SMALL_INT(exr); - tuple->items[2] = MP_OBJ_NEW_SMALL_INT(eyr); - ret->items[0] = MP_OBJ_NEW_SMALL_INT(i); - ret->items[1] = MP_OBJ_FROM_PTR(tuple); - return mp_const_true; } } else if (iface == USB_DATA_IFACE) { bool usb_connected = usb_configured() == sectrue ? true : false; diff --git a/core/embed/extmod/modtrezorio/modtrezorio-usb.h b/core/embed/extmod/modtrezorio/modtrezorio-usb.h index bdc036d57e..39e4d9e8f0 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio-usb.h +++ b/core/embed/extmod/modtrezorio/modtrezorio-usb.h @@ -190,7 +190,9 @@ STATIC mp_obj_t mod_trezorio_USB_open(mp_obj_t self, mp_obj_get_array(MP_OBJ_FROM_PTR(&o->ifaces), &iface_cnt, &iface_objs); // Initialize the USB stack - usb_init(&o->info); + if (sectrue != usb_init(&o->info)) { + mp_raise_msg(&mp_type_RuntimeError, "failed to initialize usb driver"); + } int vcp_iface_num = -1; @@ -224,7 +226,10 @@ STATIC mp_obj_t mod_trezorio_USB_open(mp_obj_t self, } // Start the USB stack - usb_start(); + if (sectrue != usb_start()) { + usb_deinit(); + mp_raise_msg(&mp_type_RuntimeError, "failed to start usb driver"); + } o->state = USB_OPENED; // If we found any VCP interfaces, use the last one for stdio, @@ -246,7 +251,6 @@ STATIC mp_obj_t mod_trezorio_USB_close(mp_obj_t self) { if (o->state != USB_OPENED) { mp_raise_msg(&mp_type_RuntimeError, "not initialized"); } - usb_stop(); usb_deinit(); mp_obj_list_set_len(MP_OBJ_FROM_PTR(&o->ifaces), 0); mp_seq_clear(o->ifaces.items, 0, o->ifaces.alloc, sizeof(*o->ifaces.items)); @@ -266,7 +270,6 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorio_USB_close_obj, STATIC mp_obj_t mod_trezorio_USB___del__(mp_obj_t self) { mp_obj_USB_t *o = MP_OBJ_TO_PTR(self); if (o->state != USB_CLOSED) { - usb_stop(); usb_deinit(); o->state = USB_CLOSED; } diff --git a/core/embed/extmod/modtrezorio/modtrezorio.c b/core/embed/extmod/modtrezorio/modtrezorio.c index 72fa781f4f..a40ae96263 100644 --- a/core/embed/extmod/modtrezorio/modtrezorio.c +++ b/core/embed/extmod/modtrezorio/modtrezorio.c @@ -35,6 +35,8 @@ // Whether USB data pins were connected on last check (USB configured) bool usb_connected_previously = true; +uint32_t last_touch_sample_time = 0; + #define CHECK_PARAM_RANGE(value, minimum, maximum) \ if (value < minimum || value > maximum) { \ mp_raise_ValueError(#value " is out of range"); \ @@ -55,9 +57,12 @@ bool usb_connected_previously = true; #include "modtrezorio-fatfs.h" #include "modtrezorio-sdcard.h" #endif +#ifdef USE_HAPTIC +#include "modtrezorio-haptic.h" +#endif /// package: trezorio.__init__ -/// from . import fatfs, sdcard +/// from . import fatfs, haptic, sdcard /// POLL_READ: int # wait until interface is readable and return read data /// POLL_WRITE: int # wait until interface is writable @@ -89,6 +94,10 @@ STATIC const mp_rom_map_elem_t mp_module_trezorio_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_sdcard), MP_ROM_PTR(&mod_trezorio_sdcard_module)}, #endif +#ifdef USE_HAPTIC + {MP_ROM_QSTR(MP_QSTR_haptic), MP_ROM_PTR(&mod_trezorio_haptic_module)}, +#endif + #ifdef USE_TOUCH {MP_ROM_QSTR(MP_QSTR_TOUCH), MP_ROM_INT(TOUCH_IFACE)}, {MP_ROM_QSTR(MP_QSTR_TOUCH_START), MP_ROM_INT((TOUCH_START >> 24) & 0xFFU)}, diff --git a/core/embed/extmod/modtrezorui/modtrezorui-display.h b/core/embed/extmod/modtrezorui/modtrezorui-display.h index 85662585a1..ee7bc030e5 100644 --- a/core/embed/extmod/modtrezorui/modtrezorui-display.h +++ b/core/embed/extmod/modtrezorui/modtrezorui-display.h @@ -18,19 +18,20 @@ */ #include "display.h" +#include "display_draw.h" +#include "fonts/fonts.h" /// class Display: /// """ /// Provide access to device display. /// """ -/// /// WIDTH: int # display width in pixels /// HEIGHT: int # display height in pixels /// FONT_MONO: int # id of monospace font /// FONT_NORMAL: int # id of normal-width font -/// FONT_BOLD: int # id of bold-width font /// FONT_DEMIBOLD: int # id of demibold font -/// +/// FONT_BOLD_UPPER: int # id of bold-width-uppercased font + typedef struct _mp_obj_Display_t { mp_obj_base_t base; } mp_obj_Display_t; @@ -128,11 +129,13 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorui_Display_backlight_obj, /// Saves current display contents to PNG file with given prefix. /// """ STATIC mp_obj_t mod_trezorui_Display_save(mp_obj_t self, mp_obj_t prefix) { +#ifdef TREZOR_EMULATOR mp_buffer_info_t pfx = {0}; mp_get_buffer_raise(prefix, &pfx, MP_BUFFER_READ); if (pfx.len > 0) { display_save(pfx.buf); } +#endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj, @@ -143,7 +146,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_trezorui_Display_save_obj, /// Clears buffers in display saving. /// """ STATIC mp_obj_t mod_trezorui_Display_clear_save(mp_obj_t self) { +#ifdef TREZOR_EMULATOR display_clear_save(); +#endif return mp_const_none; } STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_trezorui_Display_clear_save_obj, @@ -163,9 +168,13 @@ STATIC const mp_rom_map_elem_t mod_trezorui_Display_locals_dict_table[] = { {MP_ROM_QSTR(MP_QSTR_WIDTH), MP_ROM_INT(DISPLAY_RESX)}, {MP_ROM_QSTR(MP_QSTR_HEIGHT), MP_ROM_INT(DISPLAY_RESY)}, {MP_ROM_QSTR(MP_QSTR_FONT_NORMAL), MP_ROM_INT(FONT_NORMAL)}, - {MP_ROM_QSTR(MP_QSTR_FONT_BOLD), MP_ROM_INT(FONT_BOLD)}, {MP_ROM_QSTR(MP_QSTR_FONT_DEMIBOLD), MP_ROM_INT(FONT_DEMIBOLD)}, {MP_ROM_QSTR(MP_QSTR_FONT_MONO), MP_ROM_INT(FONT_MONO)}, +#ifdef FONT_BOLD_UPPER + {MP_ROM_QSTR(MP_QSTR_FONT_BOLD_UPPER), MP_ROM_INT(FONT_BOLD_UPPER)}, +#else + {MP_ROM_QSTR(MP_QSTR_FONT_BOLD_UPPER), MP_ROM_INT(FONT_BOLD)}, +#endif }; STATIC MP_DEFINE_CONST_DICT(mod_trezorui_Display_locals_dict, mod_trezorui_Display_locals_dict_table); diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils-meminfo.h b/core/embed/extmod/modtrezorutils/modtrezorutils-meminfo.h index 6c825343fd..422c83caac 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils-meminfo.h +++ b/core/embed/extmod/modtrezorutils/modtrezorutils-meminfo.h @@ -59,10 +59,10 @@ #define ATB_MASK_2 (0x30) #define ATB_MASK_3 (0xc0) -#define ATB_0_IS_FREE(a) (((a)&ATB_MASK_0) == 0) -#define ATB_1_IS_FREE(a) (((a)&ATB_MASK_1) == 0) -#define ATB_2_IS_FREE(a) (((a)&ATB_MASK_2) == 0) -#define ATB_3_IS_FREE(a) (((a)&ATB_MASK_3) == 0) +#define ATB_0_IS_FREE(a) (((a) & ATB_MASK_0) == 0) +#define ATB_1_IS_FREE(a) (((a) & ATB_MASK_1) == 0) +#define ATB_2_IS_FREE(a) (((a) & ATB_MASK_2) == 0) +#define ATB_3_IS_FREE(a) (((a) & ATB_MASK_3) == 0) #define BLOCK_SHIFT(block) (2 * ((block) & (BLOCKS_PER_ATB - 1))) #define ATB_GET_KIND(block) \ @@ -98,7 +98,7 @@ #define BLOCK_FROM_PTR(ptr) \ (((byte *)(ptr)-MP_STATE_MEM(gc_pool_start)) / BYTES_PER_BLOCK) #define PTR_FROM_BLOCK(block) \ - (((block)*BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start))) + (((block) * BYTES_PER_BLOCK + (uintptr_t)MP_STATE_MEM(gc_pool_start))) #define ATB_FROM_BLOCK(bl) ((bl) / BLOCKS_PER_ATB) // ptr should be of type void* diff --git a/core/embed/extmod/modtrezorutils/modtrezorutils.c b/core/embed/extmod/modtrezorutils/modtrezorutils.c index 004f6941af..d00e35d11f 100644 --- a/core/embed/extmod/modtrezorutils/modtrezorutils.c +++ b/core/embed/extmod/modtrezorutils/modtrezorutils.c @@ -136,9 +136,9 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_memcpy_obj, 4, 5, STATIC mp_obj_t mod_trezorutils_halt(size_t n_args, const mp_obj_t *args) { mp_buffer_info_t msg = {0}; if (n_args > 0 && mp_get_buffer(args[0], &msg, MP_BUFFER_READ)) { - ensure(secfalse, msg.buf); + error_shutdown(msg.buf); } else { - ensure(secfalse, "halt"); + error_shutdown("halt"); } return mp_const_none; } @@ -320,15 +320,15 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN( mod_trezorutils_reboot_to_bootloader); /// VersionTuple = Tuple[int, int, int, int] -/// + /// class FirmwareHeaderInfo(NamedTuple): /// version: VersionTuple /// vendor: str /// fingerprint: bytes /// hash: bytes -/// + /// mock:global -/// + /// def check_firmware_header(header : bytes) -> FirmwareHeaderInfo: /// """Parses incoming firmware header and returns information about it.""" STATIC mp_obj_t mod_trezorutils_check_firmware_header(mp_obj_t header) { @@ -390,6 +390,18 @@ STATIC mp_obj_str_t mod_trezorutils_full_name_obj = { sizeof(MODEL_FULL_NAME) - 1, (const byte *)MODEL_FULL_NAME}; +STATIC mp_obj_str_t mod_trezorutils_model_usb_manufacturer_obj = { + {&mp_type_str}, + 0, + sizeof(MODEL_USB_MANUFACTURER) - 1, + (const byte *)MODEL_USB_MANUFACTURER}; + +STATIC mp_obj_str_t mod_trezorutils_model_usb_product_obj = { + {&mp_type_str}, + 0, + sizeof(MODEL_USB_PRODUCT) - 1, + (const byte *)MODEL_USB_PRODUCT}; + STATIC mp_obj_tuple_t mod_trezorutils_version_obj = { {&mp_type_tuple}, 4, @@ -404,12 +416,18 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = { /// """Whether the hardware supports SD card.""" /// USE_BACKLIGHT: bool /// """Whether the hardware supports backlight brightness control.""" +/// USE_HAPTIC: bool +/// """Whether the hardware supports haptic feedback.""" /// USE_OPTIGA: bool /// """Whether the hardware supports Optiga secure element.""" /// MODEL: str /// """Model name.""" /// MODEL_FULL_NAME: str /// """Full name including Trezor prefix.""" +/// MODEL_USB_MANUFACTURER: str +/// """USB Manufacturer name.""" +/// MODEL_USB_PRODUCT: str +/// """USB Product name.""" /// INTERNAL_MODEL: str /// """Internal model code.""" /// EMULATOR: bool @@ -418,6 +436,8 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = { /// """Whether the firmware is Bitcoin-only.""" /// UI_LAYOUT: str /// """UI layout identifier ("tt" for model T, "tr" for models One and R).""" +/// USE_THP: bool +/// """Whether the firmware supports Trezor-Host Protocol (version 3).""" STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_trezorutils)}, @@ -456,6 +476,11 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { #else {MP_ROM_QSTR(MP_QSTR_USE_BACKLIGHT), mp_const_false}, #endif +#ifdef USE_HAPTIC + {MP_ROM_QSTR(MP_QSTR_USE_HAPTIC), mp_const_true}, +#else + {MP_ROM_QSTR(MP_QSTR_USE_HAPTIC), mp_const_false}, +#endif #ifdef USE_OPTIGA {MP_ROM_QSTR(MP_QSTR_USE_OPTIGA), mp_const_true}, #else @@ -464,6 +489,10 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { {MP_ROM_QSTR(MP_QSTR_MODEL), MP_ROM_PTR(&mod_trezorutils_model_name_obj)}, {MP_ROM_QSTR(MP_QSTR_MODEL_FULL_NAME), MP_ROM_PTR(&mod_trezorutils_full_name_obj)}, + {MP_ROM_QSTR(MP_QSTR_MODEL_USB_MANUFACTURER), + MP_ROM_PTR(&mod_trezorutils_model_usb_manufacturer_obj)}, + {MP_ROM_QSTR(MP_QSTR_MODEL_USB_PRODUCT), + MP_ROM_PTR(&mod_trezorutils_model_usb_product_obj)}, {MP_ROM_QSTR(MP_QSTR_INTERNAL_MODEL), MP_ROM_QSTR(MODEL_INTERNAL_NAME_QSTR)}, #ifdef TREZOR_EMULATOR @@ -477,10 +506,17 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = { #else {MP_ROM_QSTR(MP_QSTR_BITCOIN_ONLY), mp_const_false}, #endif +#ifdef USE_THP + {MP_ROM_QSTR(MP_QSTR_USE_THP), mp_const_true}, +#else + {MP_ROM_QSTR(MP_QSTR_USE_THP), mp_const_false}, +#endif #ifdef UI_LAYOUT_TT {MP_ROM_QSTR(MP_QSTR_UI_LAYOUT), MP_ROM_QSTR(MP_QSTR_TT)}, #elif UI_LAYOUT_TR {MP_ROM_QSTR(MP_QSTR_UI_LAYOUT), MP_ROM_QSTR(MP_QSTR_TR)}, +#elif UI_LAYOUT_MERCURY + {MP_ROM_QSTR(MP_QSTR_UI_LAYOUT), MP_ROM_QSTR(MP_QSTR_MERCURY)}, #else #error Unknown layout #endif diff --git a/core/embed/firmware/bl_check.c b/core/embed/firmware/bl_check.c index 94bef3853c..c172df62d6 100644 --- a/core/embed/firmware/bl_check.c +++ b/core/embed/firmware/bl_check.c @@ -34,73 +34,13 @@ extern const void extern const void _binary_embed_firmware_bootloaders_bootloader_bin_deflated_size; -/* -static secbool known_bootloader(const uint8_t *hash, int len) { - if (len != 32) return secfalse; - // bootloader-2.0.1.bin (padded with 0x00) - if (0 == memcmp(hash, -"\x91\x37\x46\xd0\x2d\xa7\xc4\xbe\x1d\xae\xef\xb0\x9b\x4e\x31\x88\xed\x38\x23\x5e\x0e\x31\xa7\x8c\x01\xde\x4e\xcc\xc2\xd6\x36\xb3", -32)) return sectrue; - // bootloader-2.0.1.bin (padded with 0xff) - if (0 == memcmp(hash, -"\x2f\xdb\xde\x94\x0a\xd8\x91\x1c\xbd\x07\xb0\xba\x06\x2c\x90\x84\x02\xec\x95\x19\xde\x52\x8d\x4b\xe9\xb9\xed\x30\x71\x91\xb4\xd3", -32)) return sectrue; - // bootloader-2.0.2.bin (padded with 0x00) - if (0 == memcmp(hash, -"\x2e\xf7\x47\xf8\x49\x87\x1e\xc8\xc6\x01\x35\xd6\x32\xe5\x5a\xd1\x56\x18\xf8\x64\x87\xb7\xaa\x7c\x62\x0e\xc3\x0d\x25\x69\x4e\x18", -32)) return sectrue; - // bootloader-2.0.2.bin (padded with 0xff) - if (0 == memcmp(hash, -"\xcc\x6b\x35\xc3\x8f\x29\x5c\xbd\x7d\x31\x69\xaf\xae\xf1\x61\x01\xef\xbe\x9f\x3b\x0a\xfd\xc5\x91\x70\x9b\xf5\xa0\xd5\xa4\xc5\xe0", -32)) return sectrue; - // bootloader-2.0.3.bin (padded with 0x00) - if (0 == memcmp(hash, -"\xb1\x83\xd3\x31\xc7\xff\x3d\xcf\x54\x1e\x7e\x40\xf4\x9e\xc3\x53\x4c\xcc\xf3\x8c\x35\x39\x88\x81\x65\xc0\x5c\x25\xbd\xfc\xea\x14", -32)) return sectrue; - // bootloader-2.0.3.bin (padded with 0xff) - if (0 == memcmp(hash, -"\xab\xdb\x7d\xe2\xef\x44\x66\xa7\xb7\x1f\x2b\x02\xf3\xe1\x40\xe7\xcd\xf2\x8e\xc0\xbb\x33\x04\xce\x0d\xa5\xca\x02\x57\xb6\xd4\x30", -32)) return sectrue; return secfalse; -} -*/ - -// clang-format off -// --- BEGIN GENERATED BOOTLOADER SECTION --- -// bootloader_1.bin version -#define BOOTLOADER_1_00 {0xa5, 0x5a, 0x8b, 0x88, 0x94, 0x8a, 0x33, 0x2b, 0xed, 0x0d, 0xd9, 0x5c, 0x79, 0xd5, 0xbe, 0x0c, 0x73, 0x52, 0xaa, 0xac, 0xb3, 0x4f, 0xea, 0xd0, 0xaa, 0x88, 0x33, 0x23, 0x64, 0xab, 0x77, 0x5a} -#define BOOTLOADER_1_FF {0x50, 0x6c, 0x5f, 0xd3, 0x73, 0x7b, 0x9b, 0xb7, 0xb9, 0xbf, 0xf9, 0xfa, 0xc6, 0xb9, 0x43, 0x27, 0x8b, 0x06, 0xad, 0x3a, 0xec, 0xce, 0x35, 0xa3, 0x52, 0xc3, 0x6e, 0x9e, 0x9a, 0xb3, 0x50, 0x98} -// bootloader_T1B1.bin version -#define BOOTLOADER_T1B1_00 {0xc1, 0x01, 0xd3, 0x8a, 0x00, 0x5e, 0x4f, 0x5f, 0x87, 0x1f, 0x49, 0x78, 0x24, 0x9c, 0xf9, 0x82, 0xd1, 0x91, 0x4b, 0xa6, 0x90, 0x03, 0x9c, 0x50, 0x49, 0x61, 0x10, 0x4f, 0xee, 0xe7, 0x1d, 0x7b} -#define BOOTLOADER_T1B1_FF {0xbd, 0xb2, 0xf7, 0x62, 0xfb, 0x10, 0xbb, 0x30, 0x1f, 0x95, 0xa3, 0x12, 0x6b, 0x41, 0x1f, 0x66, 0xfc, 0x57, 0x28, 0xce, 0x7f, 0x59, 0x42, 0x6c, 0x3e, 0xed, 0xf7, 0x69, 0xbb, 0x96, 0xbd, 0x4b} -// bootloader_T2B1.bin version 2.1.4.0 -#define BOOTLOADER_T2B1_00 {0x12, 0xf5, 0x51, 0x01, 0x10, 0xb3, 0x59, 0x8e, 0x73, 0x95, 0xa9, 0xa8, 0xc5, 0xbc, 0x3a, 0x53, 0xa3, 0xa8, 0xed, 0x83, 0x32, 0xc2, 0xd2, 0x5b, 0x47, 0x99, 0x27, 0x9f, 0x93, 0x8b, 0xb3, 0xd6} -#define BOOTLOADER_T2B1_FF {0x19, 0x7c, 0x2a, 0xd1, 0xba, 0x89, 0xeb, 0x2a, 0xfc, 0xe1, 0x7b, 0xf3, 0x62, 0x7d, 0xf8, 0xb2, 0x3c, 0x70, 0x16, 0x03, 0x53, 0xad, 0x8e, 0x90, 0x9b, 0x57, 0xeb, 0x4b, 0x83, 0x4d, 0xa0, 0x34} -// bootloader_T2B1_qa.bin version 2.1.4.0 -#define BOOTLOADER_T2B1_QA_00 {0x96, 0xe7, 0xfa, 0x21, 0x66, 0x81, 0x6b, 0x27, 0xf6, 0x27, 0xc1, 0x50, 0xaa, 0xf8, 0xbf, 0xac, 0xf5, 0x0d, 0x37, 0xea, 0x10, 0xa9, 0xa2, 0x0c, 0x1a, 0x58, 0xa7, 0x42, 0x23, 0x80, 0xbe, 0x40} -#define BOOTLOADER_T2B1_QA_FF {0x7c, 0xca, 0xde, 0xf6, 0x8f, 0xf8, 0x9a, 0x08, 0x35, 0x0a, 0x82, 0xe4, 0xb5, 0x76, 0x37, 0x36, 0x51, 0x33, 0x40, 0xd9, 0x66, 0x84, 0xfb, 0x1b, 0x4f, 0x89, 0x34, 0xcd, 0x6f, 0x4c, 0x03, 0x1a} -// bootloader_T2T1.bin version 2.1.4.0 -#define BOOTLOADER_T2T1_00 {0x37, 0xaf, 0xad, 0xb6, 0x55, 0x7a, 0xd3, 0x82, 0x2c, 0x7b, 0xd3, 0x41, 0x65, 0xb7, 0x4d, 0xce, 0xbe, 0x23, 0x87, 0x90, 0x93, 0x3f, 0xbc, 0x4c, 0x5a, 0x1c, 0x60, 0x8c, 0xf9, 0xf6, 0xec, 0x0c} -#define BOOTLOADER_T2T1_FF {0x5e, 0x84, 0xd3, 0xf7, 0xfd, 0x55, 0x51, 0xfd, 0x5f, 0x22, 0xc4, 0x83, 0xe2, 0x67, 0xc5, 0x1b, 0x77, 0xce, 0x49, 0xce, 0x42, 0x19, 0xe8, 0x23, 0x84, 0x4a, 0x58, 0x47, 0xaf, 0x80, 0x69, 0x86} -// bootloader_T2T1_qa.bin version 2.1.4.0 -#define BOOTLOADER_T2T1_QA_00 {0xff, 0xda, 0xfd, 0x0f, 0xe1, 0x89, 0x56, 0xb6, 0x0b, 0x6e, 0x2d, 0x67, 0xf1, 0x63, 0x8c, 0x4c, 0x4d, 0x6f, 0x97, 0xe7, 0xe0, 0xa4, 0xce, 0x76, 0xc9, 0x49, 0x0a, 0x34, 0x3e, 0xd8, 0xcb, 0x1f} -#define BOOTLOADER_T2T1_QA_FF {0xbe, 0x31, 0x71, 0x7b, 0x8b, 0x31, 0x12, 0xbd, 0x58, 0xc4, 0x81, 0x09, 0x8d, 0xd9, 0x07, 0x51, 0x5c, 0xb6, 0x3d, 0x07, 0x82, 0x00, 0x30, 0x4a, 0xeb, 0x26, 0xf0, 0xe4, 0x00, 0xd4, 0xf2, 0x9c} -// bootloader_T3T1.bin version 2.1.5.0 -#define BOOTLOADER_T3T1_00 {0xc4, 0x9f, 0xfc, 0x91, 0xab, 0x6a, 0x2c, 0x85, 0x01, 0xac, 0x98, 0x2a, 0x0a, 0x4b, 0x62, 0x2a, 0xa0, 0x70, 0x81, 0xa3, 0xaa, 0x49, 0x6b, 0x79, 0x3a, 0x0a, 0x37, 0x66, 0xbc, 0x09, 0x7c, 0x9e} -#define BOOTLOADER_T3T1_FF {0x93, 0x79, 0x40, 0xdf, 0x9f, 0xf4, 0xfe, 0xe9, 0x77, 0xb7, 0x38, 0x3a, 0x07, 0x16, 0xe5, 0xca, 0xdd, 0xcb, 0xbf, 0xd5, 0x00, 0x5a, 0x93, 0x61, 0x05, 0x71, 0xa8, 0x76, 0x86, 0x61, 0xf2, 0x3b} -// bootloader_T3T1_qa.bin version 2.1.5.0 -#define BOOTLOADER_T3T1_QA_00 {0xad, 0x43, 0x20, 0x2a, 0xf9, 0xdc, 0xce, 0x01, 0x45, 0x63, 0x22, 0x98, 0xe0, 0xfa, 0x13, 0x1e, 0x4e, 0xfb, 0xf7, 0x06, 0x81, 0x1d, 0xf0, 0x0f, 0x2d, 0xed, 0x6a, 0x26, 0x25, 0x1f, 0xbb, 0x9f} -#define BOOTLOADER_T3T1_QA_FF {0x04, 0x16, 0x00, 0x16, 0x5e, 0x22, 0x76, 0x2f, 0x60, 0x01, 0x18, 0x36, 0x7c, 0xaa, 0x32, 0x60, 0x8d, 0x98, 0x89, 0x2f, 0x41, 0x10, 0x82, 0xdf, 0x02, 0xca, 0x28, 0x85, 0xcc, 0xd1, 0xae, 0x15} -// --- END GENERATED BOOTLOADER SECTION --- - - #define CONCAT_NAME_HELPER(prefix, name, suffix) prefix##name##suffix #define CONCAT_NAME(name, var) CONCAT_NAME_HELPER(BOOTLOADER_, name, var) - #if BOOTLOADER_QA // QA bootloaders - #define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00) - #define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF) +#define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_00) +#define BOOTLOADER_FF CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _QA_FF) #else // normal bootloaders #define BOOTLOADER_00 CONCAT_NAME(MODEL_INTERNAL_NAME_TOKEN, _00) @@ -204,7 +144,7 @@ void check_and_replace_bootloader(void) { (new_bld_hdr->hw_model != 0)) { // reject non-model T bootloader // 0 represents pre-model check bootloader - ensure(secfalse, "Incompatible embedded bootloader"); + error_shutdown("Incompatible embedded bootloader"); } } // at this point, due to the previous check_image_model call, we know that the @@ -213,7 +153,7 @@ void check_and_replace_bootloader(void) { // against the firmware hw_model. else if (board_name != HW_MODEL) { // reject incompatible bootloader - ensure(secfalse, "Incompatible embedded bootloader"); + error_shutdown("Incompatible embedded bootloader"); } ensure(flash_area_erase(&BOOTLOADER_AREA, NULL), NULL); diff --git a/core/embed/firmware/bootloader_hashes.py b/core/embed/firmware/bootloader_hashes.py deleted file mode 100755 index 2661847e60..0000000000 --- a/core/embed/firmware/bootloader_hashes.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python3 -from pathlib import Path -from hashlib import blake2s - -from trezorlib.firmware.core import FirmwareImage - -ALIGNED_SIZE = 128 * 1024 - -HERE = Path(__file__).parent -BOOTLOADERS = HERE / "bootloaders" - -BL_CHECK = HERE / "bl_check.c" - -BL_CHECK_AUTO_BEGIN = "// --- BEGIN GENERATED BOOTLOADER SECTION ---\n" -BL_CHECK_AUTO_END = "// --- END GENERATED BOOTLOADER SECTION ---\n" - -PATTERN = """\ -// {name} version {version} -#define BOOTLOADER_{suffix}_00 {{{bytes_00}}} -#define BOOTLOADER_{suffix}_FF {{{bytes_ff}}} -""" - - -def aligned_digest(data: bytes, padding: bytes) -> bytes: - """Calculate digest of data, aligned to ALIGNED_SIZE with - the specified padding. - - Firmware needs to check the bootloader against a digest padded either by 0xff - (unwritten NOR-flash byte) or 0x00 (explicitly cleared byte). - """ - if len(data) > ALIGNED_SIZE: - raise ValueError(fn, "too big") - - assert len(padding) == 1 - digest_data = data + padding * (ALIGNED_SIZE - len(data)) - assert len(digest_data) == ALIGNED_SIZE - return blake2s(digest_data).digest() - - -def to_uint_array(data: bytes) -> str: - """Convert bytes to C array of uint8_t, like so: - - >>> to_uint_array(b"\\x00\\x01\\x02") - "{0x00, 0x01, 0x02}" - """ - return ", ".join([f"0x{i:02x}" for i in data]) - - -def bootloader_str(file: Path) -> str: - """From a given file, generate the relevant C definition strings from PATTERN. - - Calculates the two padded hashes, one with 0x00 and the other 0xFF, and returns - a string suitable for writing into bl_check.c. - """ - data = file.read_bytes() - - suffix = file.stem[len("bootloader_") :].upper() - bytes_00 = to_uint_array(aligned_digest(data, b"\x00")) - bytes_ff = to_uint_array(aligned_digest(data, b"\xff")) - - try: - bl = FirmwareImage.parse(data) - version_str = ".".join(str(x) for x in bl.header.version) - except Exception: - version_str = "" - - return PATTERN.format( - name=file.name, - version=version_str, - suffix=suffix, - bytes_00=bytes_00, - bytes_ff=bytes_ff, - ) - - -def main(): - bl_check_new = [] - with open(BL_CHECK) as f: - # read up to auto-begin - for line in f: - bl_check_new.append(line) - if line == BL_CHECK_AUTO_BEGIN: - break - - # write bootloader definitions - for file in sorted(BOOTLOADERS.glob("bootloader*.bin")): - bl_check_new.append(bootloader_str(file)) - - # consume up to auto-end - for line in f: - if line == BL_CHECK_AUTO_END: - bl_check_new.append(line) - break - - # read the rest - bl_check_new.extend(f) - - # write the file - BL_CHECK.write_text("".join(bl_check_new)) - - -if __name__ == "__main__": - main() diff --git a/core/embed/firmware/bootloaders/bootloader_1.bin b/core/embed/firmware/bootloaders/bootloader_1.bin deleted file mode 120000 index 6a019c96b1..0000000000 --- a/core/embed/firmware/bootloaders/bootloader_1.bin +++ /dev/null @@ -1 +0,0 @@ -../../../../legacy/firmware/bootloader.dat \ No newline at end of file diff --git a/core/embed/firmware/bootloaders/bootloader_T1B1.bin b/core/embed/firmware/bootloaders/bootloader_T1B1.bin deleted file mode 100644 index ac9d56f230..0000000000 Binary files a/core/embed/firmware/bootloaders/bootloader_T1B1.bin and /dev/null differ diff --git a/core/embed/firmware/bootloaders/bootloader_T3T1_qa.bin b/core/embed/firmware/bootloaders/bootloader_T3T1_qa.bin deleted file mode 100755 index ee0716ef1a..0000000000 Binary files a/core/embed/firmware/bootloaders/bootloader_T3T1_qa.bin and /dev/null differ diff --git a/core/embed/firmware/header.S b/core/embed/firmware/header.S index 3531e23955..f2f201cec8 100644 --- a/core/embed/firmware/header.S +++ b/core/embed/firmware/header.S @@ -29,7 +29,7 @@ g_header: .byte FIX_VERSION_BUILD // fix_vbuild .word HW_MODEL // type of the designated hardware .byte HW_REVISION // revision of the designated hardware - .byte VERSION_MONOTONIC // monotonic version of the binary + .byte FIRMWARE_MONOTONIC_VERSION // monotonic version of the binary . = . + 2 // reserved . = . + 512 // hash1 ... hash16 diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index ba35e7a993..fc59514d3c 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -60,8 +60,13 @@ #include "consumption_mask.h" #endif #ifdef USE_DMA2D +#ifdef NEW_RENDERING +#include "dma2d_bitblt.h" +#else #include "dma2d.h" #endif +#endif + #ifdef USE_BUTTON #include "button.h" #endif @@ -228,11 +233,17 @@ int main(void) { #endif optiga_init(); - optiga_open_application(); if (sectrue == secret_ok) { - optiga_sec_chan_handshake(secret, sizeof(secret)); + // If the shielded connection cannot be established, reset Optiga and + // continue without it. In this case, OID_KEY_FIDO and OID_KEY_DEV cannot be + // used, which means device and FIDO attestation will not work. + if (optiga_sec_chan_handshake(secret, sizeof(secret)) != OPTIGA_SUCCESS) { + optiga_soft_reset(); + } } memzero(secret, sizeof(secret)); + ensure(sectrue * (optiga_open_application() == OPTIGA_SUCCESS), + "Cannot initialize optiga."); #endif #if !defined TREZOR_MODEL_1 @@ -274,7 +285,7 @@ int main(void) { mp_deinit(); // Python code shouldn't ever exit, avoid black screen if it does - error_shutdown("INTERNAL ERROR", "(PE)"); + error_shutdown("(PE)"); return 0; } @@ -282,7 +293,7 @@ int main(void) { // MicroPython default exception handler void __attribute__((noreturn)) nlr_jump_fail(void *val) { - error_shutdown("INTERNAL ERROR", "(UE)"); + error_shutdown("(UE)"); } // MicroPython builtin stubs diff --git a/core/embed/firmware/memory_DISC2.ld b/core/embed/firmware/memory_DISC2.ld index ec4a5ae26c..ae6d127292 100644 --- a/core/embed/firmware/memory_DISC2.ld +++ b/core/embed/firmware/memory_DISC2.ld @@ -60,7 +60,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); @@ -89,6 +89,8 @@ SECTIONS { .data_ccm : ALIGN(4) { *(.no_dma_buffers*); . = ALIGN(4); + *(.buf*); + . = ALIGN(4); } >SRAM1 .heap : ALIGN(4) { diff --git a/core/embed/firmware/memory_T.ld b/core/embed/firmware/memory_T.ld index 8f65dd6c17..9affc00a90 100644 --- a/core/embed/firmware/memory_T.ld +++ b/core/embed/firmware/memory_T.ld @@ -87,6 +87,11 @@ SECTIONS { . = ALIGN(4); } >SRAM + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM + .heap : ALIGN(4) { . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ . = ABSOLUTE(sram_end); /* this explicitly sets the end of the heap */ diff --git a/core/embed/firmware/memory_T3B1.ld b/core/embed/firmware/memory_T3B1.ld new file mode 120000 index 0000000000..b5bfd3715e --- /dev/null +++ b/core/embed/firmware/memory_T3B1.ld @@ -0,0 +1 @@ +memory_T3T1.ld \ No newline at end of file diff --git a/core/embed/firmware/memory_T3T1.ld b/core/embed/firmware/memory_T3T1.ld index d7538891bf..35674f169d 100644 --- a/core/embed/firmware/memory_T3T1.ld +++ b/core/embed/firmware/memory_T3T1.ld @@ -87,13 +87,8 @@ SECTIONS { . = ALIGN(4); } >SRAM1 - .buf : ALIGN(4) { - *(.buf*); - . = ALIGN(4); - } >SRAM1 - .stack : ALIGN(8) { - . = 16K; /* Overflow causes UsageFault */ + . = 32K; /* Overflow causes UsageFault */ } >SRAM2 .confidential : ALIGN(512) { @@ -110,6 +105,11 @@ SECTIONS { . = ALIGN(4); } >SRAM3 + .buf : ALIGN(4) { + *(.buf*); + . = ALIGN(4); + } >SRAM3 + .heap : ALIGN(4) { . = 37K; /* this acts as a build time assertion that at least this much memory is available for heap use */ . = ABSOLUTE(sram3_end); /* this explicitly sets the end of the heap */ diff --git a/core/embed/firmware/version.h b/core/embed/firmware/version.h index 46eeb5f85c..566ba077af 100644 --- a/core/embed/firmware/version.h +++ b/core/embed/firmware/version.h @@ -1,11 +1,13 @@ +#pragma once + +#include "model_version.h" + #define VERSION_MAJOR 2 -#define VERSION_MINOR 7 -#define VERSION_PATCH 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 2 #define VERSION_BUILD 0 #define FIX_VERSION_MAJOR 2 -#define FIX_VERSION_MINOR 7 +#define FIX_VERSION_MINOR 8 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 - -#define VERSION_MONOTONIC 1 diff --git a/core/embed/lib/assert.h b/core/embed/lib/assert.h new file mode 100644 index 0000000000..511000f977 --- /dev/null +++ b/core/embed/lib/assert.h @@ -0,0 +1,55 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIB_ASSERT_H +#define LIB_ASSERT_H + +// This file overrides the standard `assert` macro to +// save space in flash memory. +// +// This file will be included instead of the standard assert.h +// as it is passed to the compiler with -include before the +// paths to the standard libraries. +// +// Our custom assert macro eliminates printing of the +// expression and prints only a short file name and line number. + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NDEBUG + +void __attribute__((noreturn)) +__fatal_error(const char *msg, const char *file, int line); + +#define assert(expr) \ + ((expr) ? (void)0 : __fatal_error("Assert", __FILE_NAME__, __LINE__)) + +#else + +#define assert(expr) ((void)0) + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // LIB_ASSERT_H diff --git a/core/embed/lib/display.c b/core/embed/lib/display_draw.c similarity index 97% rename from core/embed/lib/display.c rename to core/embed/lib/display_draw.c index 5c99bfaffc..289b2ce16c 100644 --- a/core/embed/lib/display.c +++ b/core/embed/lib/display_draw.c @@ -19,7 +19,7 @@ #define _GNU_SOURCE -#include "display.h" +#include "display_draw.h" #include "buffers.h" #include "common.h" @@ -34,9 +34,11 @@ #include "memzero.h" -#include "display_interface.h" +#include "display.h" -static struct { int x, y; } DISPLAY_OFFSET; +static struct { + int x, y; +} DISPLAY_OFFSET; // common display functions @@ -61,8 +63,8 @@ void display_clear(void) { // set MADCTL first so that we can set the window correctly next display_orientation(0); // address the complete frame memory - display_set_window(0, 0, MAX_DISPLAY_RESX - 1, MAX_DISPLAY_RESY - 1); - for (uint32_t i = 0; i < MAX_DISPLAY_RESX * MAX_DISPLAY_RESY; i++) { + display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); + for (uint32_t i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { // 2 bytes per pixel because we're using RGB 5-6-5 format PIXELDATA(0x0000); } diff --git a/core/embed/lib/display.h b/core/embed/lib/display_draw.h similarity index 95% rename from core/embed/lib/display.h rename to core/embed/lib/display_draw.h index f76c8b4cc9..dcd046681d 100644 --- a/core/embed/lib/display.h +++ b/core/embed/lib/display_draw.h @@ -17,8 +17,8 @@ * along with this program. If not, see . */ -#ifndef __DISPLAY_H__ -#define __DISPLAY_H__ +#ifndef __DISPLAY_DRAW_H__ +#define __DISPLAY_DRAW_H__ #include #include @@ -27,7 +27,6 @@ #include "buffers.h" #include "colors.h" #include TREZOR_BOARD -#include "display_interface.h" #include "fonts/fonts.h" // provided by common diff --git a/core/embed/lib/dma2d_emul.c b/core/embed/lib/dma2d_emul.c index a9ccd9d106..99fb880be0 100644 --- a/core/embed/lib/dma2d_emul.c +++ b/core/embed/lib/dma2d_emul.c @@ -18,7 +18,7 @@ */ #include "colors.h" -#include "display_interface.h" +#include "display.h" typedef enum { DMA2D_LAYER_FG = 1, diff --git a/core/embed/lib/error_handling.c b/core/embed/lib/error_handling.c new file mode 100644 index 0000000000..f93636c058 --- /dev/null +++ b/core/embed/lib/error_handling.c @@ -0,0 +1,122 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#ifdef TREZOR_EMULATOR +#include +#endif + +#include "common.h" +#include "display.h" +#include "error_handling.h" +#include "mini_printf.h" +#ifdef FANCY_FATAL_ERROR +#include "rust_ui.h" +#else +#include "terminal.h" +#endif + +#ifdef RGB16 +#define COLOR_FATAL_ERROR RGB16(0x7F, 0x00, 0x00) +#else +#define COLOR_FATAL_ERROR COLOR_BLACK +#endif + +void __attribute__((noreturn)) +error_shutdown_ex(const char *title, const char *message, const char *footer) { + if (title == NULL) { + title = "INTERNAL ERROR"; + } + if (footer == NULL) { + footer = "PLEASE VISIT\nTREZOR.IO/RSOD"; + } + +#ifdef FANCY_FATAL_ERROR + error_shutdown_rust(title, message, footer); +#else + display_orientation(0); + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + term_printf("%s\n", title); + if (message) { + term_printf("%s\n", message); + } + term_printf("\n%s\n", footer); + display_backlight(255); + trezor_shutdown(); +#endif +} + +void __attribute__((noreturn)) error_shutdown(const char *message) { + error_shutdown_ex(NULL, message, NULL); +} + +void __attribute__((noreturn)) +__fatal_error(const char *msg, const char *file, int line) { +#ifdef TREZOR_EMULATOR + fprintf(stderr, "FATAL ERROR: %s\n", msg); + if (file) { + fprintf(stderr, "file: %s:%d\n", file, line); + } + fflush(stderr); +#endif +#ifdef FANCY_FATAL_ERROR + if (msg == NULL) { + char buf[128] = {0}; + mini_snprintf(buf, sizeof(buf), "%s:%d", file, line); + msg = buf; + } + error_shutdown(msg); +#else + display_orientation(0); + term_set_color(COLOR_WHITE, COLOR_FATAL_ERROR); + term_printf("\nINTERNAL ERROR:\n"); + if (msg) { + term_printf("msg : %s\n", msg); + } + if (file) { + term_printf("file: %s:%d\n", file, line); + } +#ifdef SCM_REVISION + const uint8_t *rev = (const uint8_t *)SCM_REVISION; + term_printf("rev : %02x%02x%02x%02x%02x\n", rev[0], rev[1], rev[2], rev[3], + rev[4]); +#endif + term_printf("\nPlease contact Trezor support.\n"); + display_backlight(255); + trezor_shutdown(); +#endif +} + +void __attribute__((noreturn)) show_wipe_code_screen(void) { + error_shutdown_ex("WIPE CODE ENTERED", + "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} + +void __attribute__((noreturn)) show_pin_too_many_screen(void) { + error_shutdown_ex("TOO MANY PIN ATTEMPTS", + "All data has been erased from the device", + "PLEASE RECONNECT\nTHE DEVICE"); +} + +void __attribute__((noreturn)) show_install_restricted_screen(void) { + error_shutdown_ex("INSTALL RESTRICTED", + "Installation of custom firmware is currently restricted.", + "Please visit\ntrezor.io/bootloader"); +} diff --git a/core/embed/lib/error_handling.h b/core/embed/lib/error_handling.h new file mode 100644 index 0000000000..574309ef42 --- /dev/null +++ b/core/embed/lib/error_handling.h @@ -0,0 +1,54 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef LIB_ERROR_HANDLING_H +#define LIB_ERROR_HANDLING_H + +// Shows an error message and shuts down the device. +// +// If the title is NULL, it will be set to "INTERNAL ERROR". +// If the message is NULL, it will be ignored. +// If the footer is NULL, it will be set to "PLEASE VISIT TREZOR.IO/RSOD". +void __attribute__((noreturn)) +error_shutdown_ex(const char *title, const char *message, const char *footer); + +// Shows an error message and shuts down the device. +// +// Same as `error_shutdown_ex()` but with a default header and footer. +void __attribute__((noreturn)) error_shutdown(const char *message); + +// Do not use this function directly, use the `ensure()` macro instead. +void __attribute__((noreturn)) +__fatal_error(const char *msg, const char *file, int line); + +// Checks for an expression and if it is false, shows an error message +// and shuts down the device. +#define ensure(expr, msg) \ + (((expr) == sectrue) ? (void)0 : __fatal_error(msg, __FILE_NAME__, __LINE__)) + +// Shows WIPE CODE ENTERED screeen and shuts down the device. +void __attribute__((noreturn)) show_wipe_code_screen(void); + +// Shows TOO MANY PIN ATTEMPTS screen and shuts down the device. +void __attribute__((noreturn)) show_pin_too_many_screen(void); + +// Shows INSTALL RESTRICTED screen and shuts down the device. +void __attribute__((noreturn)) show_install_restricted_screen(void); + +#endif // LIB_ERRORS_H diff --git a/core/embed/lib/fonts/font_pixeloperator_bold_8.c b/core/embed/lib/fonts/font_pixeloperator_bold_8.c index 5bdd5e4038..76c6ce16b9 100644 --- a/core/embed/lib/fonts/font_pixeloperator_bold_8.c +++ b/core/embed/lib/fonts/font_pixeloperator_bold_8.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -6,6 +8,8 @@ // - the third, fourth and fifth bytes are advance, bearingX and bearingY of the horizontal metrics of the glyph // - the rest is packed 1-bit glyph data +// NOTE: hand-changed the width and advance of '_' to 5 + /* */ static const uint8_t Font_PixelOperator_Bold_8_glyph_32[] = { 0, 0, 4, 0, 0 }; /* ! */ static const uint8_t Font_PixelOperator_Bold_8_glyph_33[] = { 2, 7, 5, 1, 7, 255, 204 }; /* " */ static const uint8_t Font_PixelOperator_Bold_8_glyph_34[] = { 5, 3, 6, 0, 7, 222, 246 }; @@ -69,7 +73,7 @@ /* \ */ static const uint8_t Font_PixelOperator_Bold_8_glyph_92[] = { 4, 7, 5, 0, 7, 204, 102, 99, 48 }; /* ] */ static const uint8_t Font_PixelOperator_Bold_8_glyph_93[] = { 4, 7, 6, 0, 7, 243, 51, 51, 240 }; /* ^ */ static const uint8_t Font_PixelOperator_Bold_8_glyph_94[] = { 6, 4, 7, 0, 7, 49, 236, 225, 0 }; -/* _ */ static const uint8_t Font_PixelOperator_Bold_8_glyph_95[] = { 5, 1, 5, 0, 0, 248 }; +/* _ */ static const uint8_t Font_PixelOperator_Bold_8_glyph_95[] = { 5, 1, 5, 0, 0, 248 }; // width (1st), advance (3rd) changed to 5, last byte to 248 /* ` */ static const uint8_t Font_PixelOperator_Bold_8_glyph_96[] = { 3, 2, 5, 0, 7, 204 }; /* a */ static const uint8_t Font_PixelOperator_Bold_8_glyph_97[] = { 6, 5, 7, 0, 5, 120, 55, 243, 124 }; /* b */ static const uint8_t Font_PixelOperator_Bold_8_glyph_98[] = { 6, 7, 7, 0, 7, 195, 15, 179, 207, 63, 128 }; @@ -104,6 +108,8 @@ /* ? */ const uint8_t Font_PixelOperator_Bold_8_glyph_nonprintable[] = { 6, 7, 7, 0, 7, 132, 207, 57, 207, 252, 255 }; +/* ? */ const uint8_t Font_PixelOperator_Bold_8_upper_glyph_nonprintable[] = { 6, 7, 7, 0, 7, 132, 207, 57, 207, 252, 255 }; + const uint8_t * const Font_PixelOperator_Bold_8[126 + 1 - 32] = { Font_PixelOperator_Bold_8_glyph_32, Font_PixelOperator_Bold_8_glyph_33, @@ -201,3 +207,101 @@ const uint8_t * const Font_PixelOperator_Bold_8[126 + 1 - 32] = { Font_PixelOperator_Bold_8_glyph_125, Font_PixelOperator_Bold_8_glyph_126, }; + +const uint8_t * const Font_PixelOperator_Bold_8_upper[126 + 1 - 32] = { + Font_PixelOperator_Bold_8_glyph_32, + Font_PixelOperator_Bold_8_glyph_33, + Font_PixelOperator_Bold_8_glyph_34, + Font_PixelOperator_Bold_8_glyph_35, + Font_PixelOperator_Bold_8_glyph_36, + Font_PixelOperator_Bold_8_glyph_37, + Font_PixelOperator_Bold_8_glyph_38, + Font_PixelOperator_Bold_8_glyph_39, + Font_PixelOperator_Bold_8_glyph_40, + Font_PixelOperator_Bold_8_glyph_41, + Font_PixelOperator_Bold_8_glyph_42, + Font_PixelOperator_Bold_8_glyph_43, + Font_PixelOperator_Bold_8_glyph_44, + Font_PixelOperator_Bold_8_glyph_45, + Font_PixelOperator_Bold_8_glyph_46, + Font_PixelOperator_Bold_8_glyph_47, + Font_PixelOperator_Bold_8_glyph_48, + Font_PixelOperator_Bold_8_glyph_49, + Font_PixelOperator_Bold_8_glyph_50, + Font_PixelOperator_Bold_8_glyph_51, + Font_PixelOperator_Bold_8_glyph_52, + Font_PixelOperator_Bold_8_glyph_53, + Font_PixelOperator_Bold_8_glyph_54, + Font_PixelOperator_Bold_8_glyph_55, + Font_PixelOperator_Bold_8_glyph_56, + Font_PixelOperator_Bold_8_glyph_57, + Font_PixelOperator_Bold_8_glyph_58, + Font_PixelOperator_Bold_8_glyph_59, + Font_PixelOperator_Bold_8_glyph_60, + Font_PixelOperator_Bold_8_glyph_61, + Font_PixelOperator_Bold_8_glyph_62, + Font_PixelOperator_Bold_8_glyph_63, + Font_PixelOperator_Bold_8_glyph_64, + Font_PixelOperator_Bold_8_glyph_65, + Font_PixelOperator_Bold_8_glyph_66, + Font_PixelOperator_Bold_8_glyph_67, + Font_PixelOperator_Bold_8_glyph_68, + Font_PixelOperator_Bold_8_glyph_69, + Font_PixelOperator_Bold_8_glyph_70, + Font_PixelOperator_Bold_8_glyph_71, + Font_PixelOperator_Bold_8_glyph_72, + Font_PixelOperator_Bold_8_glyph_73, + Font_PixelOperator_Bold_8_glyph_74, + Font_PixelOperator_Bold_8_glyph_75, + Font_PixelOperator_Bold_8_glyph_76, + Font_PixelOperator_Bold_8_glyph_77, + Font_PixelOperator_Bold_8_glyph_78, + Font_PixelOperator_Bold_8_glyph_79, + Font_PixelOperator_Bold_8_glyph_80, + Font_PixelOperator_Bold_8_glyph_81, + Font_PixelOperator_Bold_8_glyph_82, + Font_PixelOperator_Bold_8_glyph_83, + Font_PixelOperator_Bold_8_glyph_84, + Font_PixelOperator_Bold_8_glyph_85, + Font_PixelOperator_Bold_8_glyph_86, + Font_PixelOperator_Bold_8_glyph_87, + Font_PixelOperator_Bold_8_glyph_88, + Font_PixelOperator_Bold_8_glyph_89, + Font_PixelOperator_Bold_8_glyph_90, + Font_PixelOperator_Bold_8_glyph_91, + Font_PixelOperator_Bold_8_glyph_92, + Font_PixelOperator_Bold_8_glyph_93, + Font_PixelOperator_Bold_8_glyph_94, + Font_PixelOperator_Bold_8_glyph_95, + Font_PixelOperator_Bold_8_glyph_96, + Font_PixelOperator_Bold_8_glyph_65, // a -> A + Font_PixelOperator_Bold_8_glyph_66, // b -> B + Font_PixelOperator_Bold_8_glyph_67, // c -> C + Font_PixelOperator_Bold_8_glyph_68, // d -> D + Font_PixelOperator_Bold_8_glyph_69, // e -> E + Font_PixelOperator_Bold_8_glyph_70, // f -> F + Font_PixelOperator_Bold_8_glyph_71, // g -> G + Font_PixelOperator_Bold_8_glyph_72, // h -> H + Font_PixelOperator_Bold_8_glyph_73, // i -> I + Font_PixelOperator_Bold_8_glyph_74, // j -> J + Font_PixelOperator_Bold_8_glyph_75, // k -> K + Font_PixelOperator_Bold_8_glyph_76, // l -> L + Font_PixelOperator_Bold_8_glyph_77, // m -> M + Font_PixelOperator_Bold_8_glyph_78, // n -> N + Font_PixelOperator_Bold_8_glyph_79, // o -> O + Font_PixelOperator_Bold_8_glyph_80, // p -> P + Font_PixelOperator_Bold_8_glyph_81, // q -> Q + Font_PixelOperator_Bold_8_glyph_82, // r -> R + Font_PixelOperator_Bold_8_glyph_83, // s -> S + Font_PixelOperator_Bold_8_glyph_84, // t -> T + Font_PixelOperator_Bold_8_glyph_85, // u -> U + Font_PixelOperator_Bold_8_glyph_86, // v -> V + Font_PixelOperator_Bold_8_glyph_87, // w -> W + Font_PixelOperator_Bold_8_glyph_88, // x -> X + Font_PixelOperator_Bold_8_glyph_89, // y -> Y + Font_PixelOperator_Bold_8_glyph_90, // z -> Z + Font_PixelOperator_Bold_8_glyph_123, + Font_PixelOperator_Bold_8_glyph_124, + Font_PixelOperator_Bold_8_glyph_125, + Font_PixelOperator_Bold_8_glyph_126, +}; diff --git a/core/embed/lib/fonts/font_pixeloperator_bold_8.h b/core/embed/lib/fonts/font_pixeloperator_bold_8.h index 198ebd4a43..d3b0f11a57 100644 --- a/core/embed/lib/fonts/font_pixeloperator_bold_8.h +++ b/core/embed/lib/fonts/font_pixeloperator_bold_8.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 1 @@ -8,3 +10,8 @@ #define Font_PixelOperator_Bold_8_BASELINE 1 extern const uint8_t* const Font_PixelOperator_Bold_8[126 + 1 - 32]; extern const uint8_t Font_PixelOperator_Bold_8_glyph_nonprintable[]; +#define Font_PixelOperator_Bold_8_upper_HEIGHT 8 +#define Font_PixelOperator_Bold_8_upper_MAX_HEIGHT 8 +#define Font_PixelOperator_Bold_8_upper_BASELINE 1 +extern const uint8_t* const Font_PixelOperator_Bold_8_upper[126 + 1 - 32]; +extern const uint8_t Font_PixelOperator_Bold_8_upper_glyph_nonprintable[]; diff --git a/core/embed/lib/fonts/font_pixeloperator_regular_8.c b/core/embed/lib/fonts/font_pixeloperator_regular_8.c index ba7a412dd4..5f61813307 100644 --- a/core/embed/lib/fonts/font_pixeloperator_regular_8.c +++ b/core/embed/lib/fonts/font_pixeloperator_regular_8.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -6,6 +8,8 @@ // - the third, fourth and fifth bytes are advance, bearingX and bearingY of the horizontal metrics of the glyph // - the rest is packed 1-bit glyph data +// NOTE: hand-changed the width and advance of '_' to 5 + /* */ static const uint8_t Font_PixelOperator_Regular_8_glyph_32[] = { 0, 0, 4, 0, 0 }; /* ! */ static const uint8_t Font_PixelOperator_Regular_8_glyph_33[] = { 1, 7, 4, 1, 7, 250 }; /* " */ static const uint8_t Font_PixelOperator_Regular_8_glyph_34[] = { 3, 3, 6, 1, 7, 182, 128 }; @@ -69,7 +73,7 @@ /* \ */ static const uint8_t Font_PixelOperator_Regular_8_glyph_92[] = { 3, 7, 4, 0, 7, 145, 36, 72 }; /* ] */ static const uint8_t Font_PixelOperator_Regular_8_glyph_93[] = { 3, 7, 6, 0, 7, 228, 146, 120 }; /* ^ */ static const uint8_t Font_PixelOperator_Regular_8_glyph_94[] = { 5, 3, 6, 0, 7, 34, 162 }; -/* _ */ static const uint8_t Font_PixelOperator_Regular_8_glyph_95[] = { 5, 1, 5, 0, 0, 248 }; +/* _ */ static const uint8_t Font_PixelOperator_Regular_8_glyph_95[] = { 5, 1, 5, 0, 0, 248 }; // width (1st), advance (3rd) changed to 5, last byte to 248 /* ` */ static const uint8_t Font_PixelOperator_Regular_8_glyph_96[] = { 2, 2, 4, 0, 7, 144 }; /* a */ static const uint8_t Font_PixelOperator_Regular_8_glyph_97[] = { 5, 5, 6, 0, 5, 112, 95, 23, 128 }; /* b */ static const uint8_t Font_PixelOperator_Regular_8_glyph_98[] = { 5, 7, 6, 0, 7, 132, 61, 24, 199, 192 }; @@ -104,6 +108,8 @@ /* ? */ const uint8_t Font_PixelOperator_Regular_8_glyph_nonprintable[] = { 5, 7, 6, 0, 7, 139, 189, 221, 255, 127 }; +/* ? */ const uint8_t Font_PixelOperator_Regular_8_upper_glyph_nonprintable[] = { 5, 7, 6, 0, 7, 139, 189, 221, 255, 127 }; + const uint8_t * const Font_PixelOperator_Regular_8[126 + 1 - 32] = { Font_PixelOperator_Regular_8_glyph_32, Font_PixelOperator_Regular_8_glyph_33, @@ -201,3 +207,101 @@ const uint8_t * const Font_PixelOperator_Regular_8[126 + 1 - 32] = { Font_PixelOperator_Regular_8_glyph_125, Font_PixelOperator_Regular_8_glyph_126, }; + +const uint8_t * const Font_PixelOperator_Regular_8_upper[126 + 1 - 32] = { + Font_PixelOperator_Regular_8_glyph_32, + Font_PixelOperator_Regular_8_glyph_33, + Font_PixelOperator_Regular_8_glyph_34, + Font_PixelOperator_Regular_8_glyph_35, + Font_PixelOperator_Regular_8_glyph_36, + Font_PixelOperator_Regular_8_glyph_37, + Font_PixelOperator_Regular_8_glyph_38, + Font_PixelOperator_Regular_8_glyph_39, + Font_PixelOperator_Regular_8_glyph_40, + Font_PixelOperator_Regular_8_glyph_41, + Font_PixelOperator_Regular_8_glyph_42, + Font_PixelOperator_Regular_8_glyph_43, + Font_PixelOperator_Regular_8_glyph_44, + Font_PixelOperator_Regular_8_glyph_45, + Font_PixelOperator_Regular_8_glyph_46, + Font_PixelOperator_Regular_8_glyph_47, + Font_PixelOperator_Regular_8_glyph_48, + Font_PixelOperator_Regular_8_glyph_49, + Font_PixelOperator_Regular_8_glyph_50, + Font_PixelOperator_Regular_8_glyph_51, + Font_PixelOperator_Regular_8_glyph_52, + Font_PixelOperator_Regular_8_glyph_53, + Font_PixelOperator_Regular_8_glyph_54, + Font_PixelOperator_Regular_8_glyph_55, + Font_PixelOperator_Regular_8_glyph_56, + Font_PixelOperator_Regular_8_glyph_57, + Font_PixelOperator_Regular_8_glyph_58, + Font_PixelOperator_Regular_8_glyph_59, + Font_PixelOperator_Regular_8_glyph_60, + Font_PixelOperator_Regular_8_glyph_61, + Font_PixelOperator_Regular_8_glyph_62, + Font_PixelOperator_Regular_8_glyph_63, + Font_PixelOperator_Regular_8_glyph_64, + Font_PixelOperator_Regular_8_glyph_65, + Font_PixelOperator_Regular_8_glyph_66, + Font_PixelOperator_Regular_8_glyph_67, + Font_PixelOperator_Regular_8_glyph_68, + Font_PixelOperator_Regular_8_glyph_69, + Font_PixelOperator_Regular_8_glyph_70, + Font_PixelOperator_Regular_8_glyph_71, + Font_PixelOperator_Regular_8_glyph_72, + Font_PixelOperator_Regular_8_glyph_73, + Font_PixelOperator_Regular_8_glyph_74, + Font_PixelOperator_Regular_8_glyph_75, + Font_PixelOperator_Regular_8_glyph_76, + Font_PixelOperator_Regular_8_glyph_77, + Font_PixelOperator_Regular_8_glyph_78, + Font_PixelOperator_Regular_8_glyph_79, + Font_PixelOperator_Regular_8_glyph_80, + Font_PixelOperator_Regular_8_glyph_81, + Font_PixelOperator_Regular_8_glyph_82, + Font_PixelOperator_Regular_8_glyph_83, + Font_PixelOperator_Regular_8_glyph_84, + Font_PixelOperator_Regular_8_glyph_85, + Font_PixelOperator_Regular_8_glyph_86, + Font_PixelOperator_Regular_8_glyph_87, + Font_PixelOperator_Regular_8_glyph_88, + Font_PixelOperator_Regular_8_glyph_89, + Font_PixelOperator_Regular_8_glyph_90, + Font_PixelOperator_Regular_8_glyph_91, + Font_PixelOperator_Regular_8_glyph_92, + Font_PixelOperator_Regular_8_glyph_93, + Font_PixelOperator_Regular_8_glyph_94, + Font_PixelOperator_Regular_8_glyph_95, + Font_PixelOperator_Regular_8_glyph_96, + Font_PixelOperator_Regular_8_glyph_65, // a -> A + Font_PixelOperator_Regular_8_glyph_66, // b -> B + Font_PixelOperator_Regular_8_glyph_67, // c -> C + Font_PixelOperator_Regular_8_glyph_68, // d -> D + Font_PixelOperator_Regular_8_glyph_69, // e -> E + Font_PixelOperator_Regular_8_glyph_70, // f -> F + Font_PixelOperator_Regular_8_glyph_71, // g -> G + Font_PixelOperator_Regular_8_glyph_72, // h -> H + Font_PixelOperator_Regular_8_glyph_73, // i -> I + Font_PixelOperator_Regular_8_glyph_74, // j -> J + Font_PixelOperator_Regular_8_glyph_75, // k -> K + Font_PixelOperator_Regular_8_glyph_76, // l -> L + Font_PixelOperator_Regular_8_glyph_77, // m -> M + Font_PixelOperator_Regular_8_glyph_78, // n -> N + Font_PixelOperator_Regular_8_glyph_79, // o -> O + Font_PixelOperator_Regular_8_glyph_80, // p -> P + Font_PixelOperator_Regular_8_glyph_81, // q -> Q + Font_PixelOperator_Regular_8_glyph_82, // r -> R + Font_PixelOperator_Regular_8_glyph_83, // s -> S + Font_PixelOperator_Regular_8_glyph_84, // t -> T + Font_PixelOperator_Regular_8_glyph_85, // u -> U + Font_PixelOperator_Regular_8_glyph_86, // v -> V + Font_PixelOperator_Regular_8_glyph_87, // w -> W + Font_PixelOperator_Regular_8_glyph_88, // x -> X + Font_PixelOperator_Regular_8_glyph_89, // y -> Y + Font_PixelOperator_Regular_8_glyph_90, // z -> Z + Font_PixelOperator_Regular_8_glyph_123, + Font_PixelOperator_Regular_8_glyph_124, + Font_PixelOperator_Regular_8_glyph_125, + Font_PixelOperator_Regular_8_glyph_126, +}; diff --git a/core/embed/lib/fonts/font_pixeloperator_regular_8.h b/core/embed/lib/fonts/font_pixeloperator_regular_8.h index ddd01b0ee7..2565d87905 100644 --- a/core/embed/lib/fonts/font_pixeloperator_regular_8.h +++ b/core/embed/lib/fonts/font_pixeloperator_regular_8.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 1 @@ -8,3 +10,8 @@ #define Font_PixelOperator_Regular_8_BASELINE 1 extern const uint8_t* const Font_PixelOperator_Regular_8[126 + 1 - 32]; extern const uint8_t Font_PixelOperator_Regular_8_glyph_nonprintable[]; +#define Font_PixelOperator_Regular_8_upper_HEIGHT 8 +#define Font_PixelOperator_Regular_8_upper_MAX_HEIGHT 8 +#define Font_PixelOperator_Regular_8_upper_BASELINE 1 +extern const uint8_t* const Font_PixelOperator_Regular_8_upper[126 + 1 - 32]; +extern const uint8_t Font_PixelOperator_Regular_8_upper_glyph_nonprintable[]; diff --git a/core/embed/lib/fonts/font_pixeloperatormono_regular_8.c b/core/embed/lib/fonts/font_pixeloperatormono_regular_8.c index 79baa6a09a..0f8ea4e9cd 100644 --- a/core/embed/lib/fonts/font_pixeloperatormono_regular_8.c +++ b/core/embed/lib/fonts/font_pixeloperatormono_regular_8.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_pixeloperatormono_regular_8.h b/core/embed/lib/fonts/font_pixeloperatormono_regular_8.h index 27a730c8bf..ce157770fd 100644 --- a/core/embed/lib/fonts/font_pixeloperatormono_regular_8.h +++ b/core/embed/lib/fonts/font_pixeloperatormono_regular_8.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 1 diff --git a/core/embed/lib/fonts/font_roboto_bold_20.c b/core/embed/lib/fonts/font_roboto_bold_20.c index 225385bca3..da87d94e85 100644 --- a/core/embed/lib/fonts/font_roboto_bold_20.c +++ b/core/embed/lib/fonts/font_roboto_bold_20.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_roboto_bold_20.h b/core/embed/lib/fonts/font_roboto_bold_20.h index 8469473513..f922ba6600 100644 --- a/core/embed/lib/fonts/font_roboto_bold_20.h +++ b/core/embed/lib/fonts/font_roboto_bold_20.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_roboto_regular_20.c b/core/embed/lib/fonts/font_roboto_regular_20.c index 64f3d68700..f4370a6e6d 100644 --- a/core/embed/lib/fonts/font_roboto_regular_20.c +++ b/core/embed/lib/fonts/font_roboto_regular_20.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_roboto_regular_20.h b/core/embed/lib/fonts/font_roboto_regular_20.h index ac18ed1f33..8eeb509837 100644 --- a/core/embed/lib/fonts/font_roboto_regular_20.h +++ b/core/embed/lib/fonts/font_roboto_regular_20.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_robotomono_medium_20.c b/core/embed/lib/fonts/font_robotomono_medium_20.c index 72884c1b22..c08fc3fb0a 100644 --- a/core/embed/lib/fonts/font_robotomono_medium_20.c +++ b/core/embed/lib/fonts/font_robotomono_medium_20.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_robotomono_medium_20.h b/core/embed/lib/fonts/font_robotomono_medium_20.h index b371bca009..7b43d298fc 100644 --- a/core/embed/lib/fonts/font_robotomono_medium_20.h +++ b/core/embed/lib/fonts/font_robotomono_medium_20.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_robotomono_medium_21.c b/core/embed/lib/fonts/font_robotomono_medium_21.c index bdb5b81efb..50077e6ebd 100644 --- a/core/embed/lib/fonts/font_robotomono_medium_21.c +++ b/core/embed/lib/fonts/font_robotomono_medium_21.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_robotomono_medium_21.h b/core/embed/lib/fonts/font_robotomono_medium_21.h index 2ae5de2b27..224fb3762a 100644 --- a/core/embed/lib/fonts/font_robotomono_medium_21.h +++ b/core/embed/lib/fonts/font_robotomono_medium_21.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_tthoves_bold_17.c b/core/embed/lib/fonts/font_tthoves_bold_17.c index 992febaa25..d8b3138e3c 100644 --- a/core/embed/lib/fonts/font_tthoves_bold_17.c +++ b/core/embed/lib/fonts/font_tthoves_bold_17.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -71,40 +73,14 @@ /* ^ */ static const uint8_t Font_TTHoves_Bold_17_glyph_94[] = { 8, 5, 8, 0, 12, 0, 251, 159, 0, 16, 255, 255, 0, 112, 207, 253, 5, 192, 111, 248, 10, 242, 31, 242, 31 }; /* _ */ static const uint8_t Font_TTHoves_Bold_17_glyph_95[] = { 9, 3, 8, 0, 0, 82, 85, 85, 85, 0, 245, 255, 255, 255, 1, 245, 255, 255, 255, 1 }; /* ` */ static const uint8_t Font_TTHoves_Bold_17_glyph_96[] = { 5, 3, 5, 0, 13, 114, 23, 0, 176, 175, 0, 0, 253, 5 }; -/* a */ static const uint8_t Font_TTHoves_Bold_17_glyph_97[] = { 9, 9, 10, 0, 9, 0, 214, 239, 42, 0, 128, 255, 255, 239, 1, 192, 172, 114, 255, 7, 0, 0, 0, 255, 9, 48, 235, 255, 255, 10, 241, 239, 187, 255, 10, 245, 95, 80, 255, 10, 242, 255, 255, 255, 10, 48, 252, 158, 250, 10 }; -/* b */ static const uint8_t Font_TTHoves_Bold_17_glyph_98[] = { 10, 12, 11, 1, 12, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 171, 238, 26, 0, 254, 255, 255, 239, 1, 254, 207, 167, 255, 10, 254, 14, 0, 251, 14, 254, 10, 0, 247, 15, 254, 13, 0, 251, 14, 254, 207, 166, 255, 10, 254, 255, 255, 239, 1, 254, 168, 238, 26, 0 }; -/* c */ static const uint8_t Font_TTHoves_Bold_17_glyph_99[] = { 10, 9, 10, 0, 9, 0, 178, 254, 76, 0, 64, 255, 255, 255, 6, 224, 255, 120, 254, 31, 243, 111, 0, 147, 57, 245, 47, 0, 0, 0, 243, 111, 0, 131, 56, 224, 255, 120, 254, 31, 64, 255, 255, 255, 6, 0, 179, 254, 76, 0 }; -/* d */ static const uint8_t Font_TTHoves_Bold_17_glyph_100[] = { 10, 12, 11, 0, 12, 0, 0, 0, 240, 159, 0, 0, 0, 240, 159, 0, 0, 0, 240, 159, 0, 179, 238, 247, 159, 80, 255, 255, 255, 159, 224, 255, 120, 254, 159, 243, 111, 0, 243, 159, 245, 47, 0, 240, 159, 243, 111, 0, 243, 159, 224, 255, 120, 254, 159, 80, 255, 255, 255, 159, 0, 179, 239, 183, 159 }; -/* e */ static const uint8_t Font_TTHoves_Bold_17_glyph_101[] = { 10, 9, 10, 0, 9, 0, 179, 238, 75, 0, 64, 255, 255, 255, 6, 224, 207, 18, 250, 47, 243, 175, 136, 249, 111, 245, 255, 255, 255, 127, 243, 95, 0, 0, 0, 224, 223, 34, 201, 28, 64, 255, 255, 255, 6, 0, 178, 238, 75, 0 }; -/* f */ static const uint8_t Font_TTHoves_Bold_17_glyph_102[] = { 7, 13, 7, 0, 13, 0, 212, 255, 4, 0, 255, 255, 4, 32, 255, 25, 0, 32, 255, 6, 0, 247, 255, 255, 4, 247, 255, 255, 4, 115, 255, 106, 1, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0 }; -/* g */ static const uint8_t Font_TTHoves_Bold_17_glyph_103[] = { 10, 13, 10, 0, 9, 0, 197, 223, 245, 63, 96, 255, 255, 255, 63, 241, 255, 152, 255, 63, 243, 111, 0, 248, 63, 245, 47, 0, 245, 63, 244, 111, 0, 248, 63, 241, 255, 135, 255, 63, 112, 255, 255, 255, 63, 0, 197, 223, 249, 63, 32, 2, 0, 246, 63, 241, 223, 84, 253, 15, 112, 255, 255, 255, 8, 0, 197, 239, 92, 0 }; -/* h */ static const uint8_t Font_TTHoves_Bold_17_glyph_104[] = { 9, 12, 10, 1, 12, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 171, 239, 25, 0, 254, 255, 255, 207, 0, 254, 207, 249, 255, 3, 254, 14, 80, 255, 6, 254, 10, 32, 255, 6, 254, 10, 16, 255, 6, 254, 10, 16, 255, 6, 254, 10, 16, 255, 6, 254, 10, 16, 255, 6 }; -/* i */ static const uint8_t Font_TTHoves_Bold_17_glyph_105[] = { 3, 13, 5, 1, 13, 51, 1, 255, 8, 255, 8, 0, 0, 255, 8, 255, 8, 255, 8, 255, 8, 255, 8, 255, 8, 255, 8, 255, 8, 255, 8 }; -/* j */ static const uint8_t Font_TTHoves_Bold_17_glyph_106[] = { 5, 17, 6, 0, 13, 0, 51, 1, 0, 255, 8, 0, 255, 8, 0, 0, 0, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 117, 255, 8, 253, 255, 6, 253, 175, 0 }; -/* k */ static const uint8_t Font_TTHoves_Bold_17_glyph_107[] = { 9, 12, 9, 1, 12, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 10, 0, 0, 0, 254, 10, 176, 255, 2, 254, 10, 247, 111, 0, 254, 58, 255, 10, 0, 254, 235, 223, 0, 0, 254, 255, 111, 0, 0, 254, 202, 239, 1, 0, 254, 42, 255, 12, 0, 254, 10, 245, 143, 0, 254, 10, 144, 255, 4 }; -/* l */ static const uint8_t Font_TTHoves_Bold_17_glyph_108[] = { 3, 12, 5, 1, 12, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10, 254, 10 }; -/* m */ static const uint8_t Font_TTHoves_Bold_17_glyph_109[] = { 13, 9, 15, 1, 9, 255, 167, 206, 67, 252, 60, 0, 255, 255, 255, 255, 255, 255, 2, 255, 159, 252, 255, 186, 255, 9, 255, 11, 240, 207, 0, 254, 11, 255, 8, 224, 175, 0, 252, 12, 255, 8, 224, 175, 0, 252, 12, 255, 8, 224, 175, 0, 252, 12, 255, 8, 224, 175, 0, 252, 12, 255, 8, 224, 175, 0, 252, 12 }; -/* n */ static const uint8_t Font_TTHoves_Bold_17_glyph_110[] = { 9, 9, 10, 1, 9, 255, 183, 239, 8, 0, 255, 255, 255, 175, 0, 255, 191, 249, 255, 2, 255, 12, 112, 255, 4, 255, 9, 48, 255, 5, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5 }; -/* o */ static const uint8_t Font_TTHoves_Bold_17_glyph_111[] = { 10, 9, 10, 0, 9, 0, 178, 238, 75, 0, 64, 255, 255, 255, 7, 224, 255, 120, 254, 47, 243, 111, 0, 243, 111, 245, 47, 0, 240, 143, 243, 111, 0, 243, 111, 224, 255, 120, 254, 47, 64, 255, 255, 255, 7, 0, 179, 238, 75, 0 }; -/* p */ static const uint8_t Font_TTHoves_Bold_17_glyph_112[] = { 10, 13, 11, 1, 9, 255, 182, 223, 9, 0, 255, 255, 255, 223, 0, 255, 191, 183, 255, 8, 255, 12, 0, 252, 13, 255, 9, 0, 249, 15, 255, 13, 0, 252, 13, 255, 191, 182, 255, 8, 255, 255, 255, 223, 0, 255, 187, 223, 25, 0, 255, 8, 0, 0, 0, 255, 8, 0, 0, 0, 255, 8, 0, 0, 0, 255, 8, 0, 0, 0 }; -/* q */ static const uint8_t Font_TTHoves_Bold_17_glyph_113[] = { 10, 13, 11, 0, 9, 0, 179, 238, 184, 159, 80, 255, 255, 255, 159, 224, 255, 120, 254, 159, 243, 111, 0, 243, 159, 245, 47, 0, 240, 159, 243, 111, 0, 243, 159, 224, 255, 120, 254, 159, 80, 255, 255, 255, 159, 0, 179, 239, 248, 159, 0, 0, 0, 240, 159, 0, 0, 0, 240, 159, 0, 0, 0, 240, 159, 0, 0, 0, 240, 159 }; -/* r */ static const uint8_t Font_TTHoves_Bold_17_glyph_114[] = { 6, 9, 7, 1, 9, 255, 218, 159, 255, 255, 159, 255, 159, 54, 255, 11, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0, 255, 8, 0 }; -/* s */ static const uint8_t Font_TTHoves_Bold_17_glyph_115[] = { 9, 9, 9, 0, 9, 48, 234, 223, 6, 0, 242, 255, 255, 143, 0, 246, 63, 128, 187, 0, 245, 207, 88, 1, 0, 144, 255, 255, 111, 0, 0, 65, 214, 255, 0, 214, 29, 112, 255, 1, 225, 255, 254, 191, 0, 32, 235, 223, 8, 0 }; -/* t */ static const uint8_t Font_TTHoves_Bold_17_glyph_116[] = { 7, 12, 7, 0, 12, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 247, 255, 255, 5, 247, 255, 255, 5, 115, 255, 106, 2, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 91, 2, 0, 255, 255, 5, 0, 213, 255, 5 }; -/* u */ static const uint8_t Font_TTHoves_Bold_17_glyph_117[] = { 9, 9, 10, 1, 9, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5, 255, 8, 48, 255, 5, 255, 9, 48, 255, 5, 255, 12, 96, 255, 5, 252, 191, 249, 255, 5, 245, 255, 255, 255, 5, 80, 253, 109, 255, 5 }; -/* v */ static const uint8_t Font_TTHoves_Bold_17_glyph_118[] = { 10, 9, 9, 0, 9, 252, 13, 0, 248, 31, 247, 47, 0, 253, 12, 241, 127, 32, 255, 7, 192, 207, 96, 255, 2, 112, 255, 177, 207, 0, 32, 255, 247, 127, 0, 0, 253, 255, 47, 0, 0, 248, 255, 13, 0, 0, 243, 255, 8, 0 }; -/* w */ static const uint8_t Font_TTHoves_Bold_17_glyph_119[] = { 14, 9, 14, 0, 9, 251, 14, 128, 255, 4, 242, 127, 247, 47, 192, 255, 8, 246, 63, 243, 95, 240, 255, 12, 250, 15, 240, 159, 244, 255, 15, 253, 11, 176, 223, 248, 217, 95, 255, 7, 112, 255, 255, 149, 255, 255, 3, 48, 255, 255, 81, 255, 255, 0, 0, 255, 223, 16, 255, 191, 0, 0, 251, 175, 0, 254, 127, 0 }; -/* x */ static const uint8_t Font_TTHoves_Bold_17_glyph_120[] = { 11, 9, 10, 0, 9, 160, 255, 2, 242, 175, 0, 16, 255, 9, 249, 31, 0, 0, 247, 63, 255, 7, 0, 0, 224, 255, 239, 0, 0, 0, 96, 255, 111, 0, 0, 0, 176, 255, 191, 0, 0, 0, 246, 143, 255, 6, 0, 32, 255, 10, 250, 47, 0, 176, 239, 1, 225, 191, 0 }; -/* y */ static const uint8_t Font_TTHoves_Bold_17_glyph_121[] = { 11, 13, 10, 0, 9, 224, 207, 0, 112, 255, 4, 144, 255, 2, 176, 239, 0, 48, 255, 7, 240, 159, 0, 0, 253, 13, 244, 79, 0, 0, 248, 47, 249, 14, 0, 0, 242, 143, 253, 10, 0, 0, 208, 255, 255, 4, 0, 0, 112, 255, 255, 0, 0, 0, 32, 255, 175, 0, 0, 0, 0, 252, 95, 0, 0, 0, 101, 253, 15, 0, 0, 0, 255, 255, 9, 0, 0, 0, 255, 174, 1, 0, 0 }; -/* z */ static const uint8_t Font_TTHoves_Bold_17_glyph_122[] = { 8, 9, 9, 0, 9, 245, 255, 255, 239, 245, 255, 255, 239, 98, 102, 254, 175, 0, 144, 255, 12, 0, 247, 223, 1, 80, 255, 46, 0, 243, 255, 89, 85, 246, 255, 255, 255, 246, 255, 255, 255 }; /* { */ static const uint8_t Font_TTHoves_Bold_17_glyph_123[] = { 7, 17, 7, 0, 13, 0, 16, 67, 0, 0, 245, 255, 1, 0, 254, 255, 1, 16, 255, 10, 0, 32, 255, 6, 0, 32, 255, 6, 0, 48, 255, 6, 0, 211, 255, 3, 0, 245, 110, 0, 0, 245, 175, 0, 0, 177, 255, 4, 0, 32, 255, 6, 0, 32, 255, 6, 0, 32, 255, 6, 0, 16, 255, 76, 0, 0, 253, 255, 1, 0, 178, 255, 1 }; /* | */ static const uint8_t Font_TTHoves_Bold_17_glyph_124[] = { 3, 16, 7, 2, 12, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9, 255, 9 }; /* } */ static const uint8_t Font_TTHoves_Bold_17_glyph_125[] = { 7, 17, 7, 0, 13, 65, 3, 0, 0, 246, 223, 1, 0, 246, 255, 10, 0, 16, 254, 13, 0, 0, 251, 13, 0, 0, 251, 13, 0, 0, 251, 14, 0, 0, 248, 207, 0, 0, 128, 255, 0, 0, 210, 255, 0, 0, 249, 127, 0, 0, 251, 14, 0, 0, 251, 13, 0, 0, 251, 13, 0, 81, 255, 12, 0, 246, 255, 8, 0, 246, 158, 0, 0 }; /* ~ */ static const uint8_t Font_TTHoves_Bold_17_glyph_126[] = { 10, 4, 10, 0, 7, 0, 98, 2, 0, 0, 128, 255, 159, 246, 143, 242, 255, 255, 255, 79, 245, 63, 180, 239, 7 }; -/* ? */ const uint8_t Font_TTHoves_Bold_17_glyph_nonprintable[] = { 9, 12, 9, 0, 12, 255, 40, 32, 230, 255, 63, 0, 0, 16, 254, 10, 32, 39, 0, 248, 90, 213, 207, 0, 246, 255, 255, 95, 0, 249, 255, 223, 2, 96, 255, 255, 95, 0, 250, 255, 255, 47, 64, 255, 255, 255, 239, 238, 255, 255, 255, 63, 99, 255, 255, 255, 15, 48, 255, 255, 255, 15, 48, 255, 255 }; +/* ? */ const uint8_t Font_TTHoves_Bold_17_upper_glyph_nonprintable[] = { 9, 12, 9, 0, 12, 255, 40, 32, 230, 255, 63, 0, 0, 16, 254, 10, 32, 39, 0, 248, 90, 213, 207, 0, 246, 255, 255, 95, 0, 249, 255, 223, 2, 96, 255, 255, 95, 0, 250, 255, 255, 47, 64, 255, 255, 255, 239, 238, 255, 255, 255, 63, 99, 255, 255, 255, 15, 48, 255, 255, 255, 15, 48, 255, 255 }; -const uint8_t * const Font_TTHoves_Bold_17[126 + 1 - 32] = { +const uint8_t * const Font_TTHoves_Bold_17_upper[126 + 1 - 32] = { Font_TTHoves_Bold_17_glyph_32, Font_TTHoves_Bold_17_glyph_33, Font_TTHoves_Bold_17_glyph_34, @@ -170,32 +146,32 @@ const uint8_t * const Font_TTHoves_Bold_17[126 + 1 - 32] = { Font_TTHoves_Bold_17_glyph_94, Font_TTHoves_Bold_17_glyph_95, Font_TTHoves_Bold_17_glyph_96, - Font_TTHoves_Bold_17_glyph_97, - Font_TTHoves_Bold_17_glyph_98, - Font_TTHoves_Bold_17_glyph_99, - Font_TTHoves_Bold_17_glyph_100, - Font_TTHoves_Bold_17_glyph_101, - Font_TTHoves_Bold_17_glyph_102, - Font_TTHoves_Bold_17_glyph_103, - Font_TTHoves_Bold_17_glyph_104, - Font_TTHoves_Bold_17_glyph_105, - Font_TTHoves_Bold_17_glyph_106, - Font_TTHoves_Bold_17_glyph_107, - Font_TTHoves_Bold_17_glyph_108, - Font_TTHoves_Bold_17_glyph_109, - Font_TTHoves_Bold_17_glyph_110, - Font_TTHoves_Bold_17_glyph_111, - Font_TTHoves_Bold_17_glyph_112, - Font_TTHoves_Bold_17_glyph_113, - Font_TTHoves_Bold_17_glyph_114, - Font_TTHoves_Bold_17_glyph_115, - Font_TTHoves_Bold_17_glyph_116, - Font_TTHoves_Bold_17_glyph_117, - Font_TTHoves_Bold_17_glyph_118, - Font_TTHoves_Bold_17_glyph_119, - Font_TTHoves_Bold_17_glyph_120, - Font_TTHoves_Bold_17_glyph_121, - Font_TTHoves_Bold_17_glyph_122, + Font_TTHoves_Bold_17_glyph_65, // a -> A + Font_TTHoves_Bold_17_glyph_66, // b -> B + Font_TTHoves_Bold_17_glyph_67, // c -> C + Font_TTHoves_Bold_17_glyph_68, // d -> D + Font_TTHoves_Bold_17_glyph_69, // e -> E + Font_TTHoves_Bold_17_glyph_70, // f -> F + Font_TTHoves_Bold_17_glyph_71, // g -> G + Font_TTHoves_Bold_17_glyph_72, // h -> H + Font_TTHoves_Bold_17_glyph_73, // i -> I + Font_TTHoves_Bold_17_glyph_74, // j -> J + Font_TTHoves_Bold_17_glyph_75, // k -> K + Font_TTHoves_Bold_17_glyph_76, // l -> L + Font_TTHoves_Bold_17_glyph_77, // m -> M + Font_TTHoves_Bold_17_glyph_78, // n -> N + Font_TTHoves_Bold_17_glyph_79, // o -> O + Font_TTHoves_Bold_17_glyph_80, // p -> P + Font_TTHoves_Bold_17_glyph_81, // q -> Q + Font_TTHoves_Bold_17_glyph_82, // r -> R + Font_TTHoves_Bold_17_glyph_83, // s -> S + Font_TTHoves_Bold_17_glyph_84, // t -> T + Font_TTHoves_Bold_17_glyph_85, // u -> U + Font_TTHoves_Bold_17_glyph_86, // v -> V + Font_TTHoves_Bold_17_glyph_87, // w -> W + Font_TTHoves_Bold_17_glyph_88, // x -> X + Font_TTHoves_Bold_17_glyph_89, // y -> Y + Font_TTHoves_Bold_17_glyph_90, // z -> Z Font_TTHoves_Bold_17_glyph_123, Font_TTHoves_Bold_17_glyph_124, Font_TTHoves_Bold_17_glyph_125, diff --git a/core/embed/lib/fonts/font_tthoves_bold_17.h b/core/embed/lib/fonts/font_tthoves_bold_17.h index e415b9378b..94ecd370d7 100644 --- a/core/embed/lib/fonts/font_tthoves_bold_17.h +++ b/core/embed/lib/fonts/font_tthoves_bold_17.h @@ -1,10 +1,12 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 #error Wrong TREZOR_FONT_BPP (expected 4) #endif -#define Font_TTHoves_Bold_17_HEIGHT 17 -#define Font_TTHoves_Bold_17_MAX_HEIGHT 18 -#define Font_TTHoves_Bold_17_BASELINE 4 -extern const uint8_t* const Font_TTHoves_Bold_17[126 + 1 - 32]; -extern const uint8_t Font_TTHoves_Bold_17_glyph_nonprintable[]; +#define Font_TTHoves_Bold_17_upper_HEIGHT 17 +#define Font_TTHoves_Bold_17_upper_MAX_HEIGHT 18 +#define Font_TTHoves_Bold_17_upper_BASELINE 4 +extern const uint8_t* const Font_TTHoves_Bold_17_upper[126 + 1 - 32]; +extern const uint8_t Font_TTHoves_Bold_17_upper_glyph_nonprintable[]; diff --git a/core/embed/lib/fonts/font_tthoves_demibold_21.c b/core/embed/lib/fonts/font_tthoves_demibold_21.c index 4014a6fb5a..de02f2ba80 100644 --- a/core/embed/lib/fonts/font_tthoves_demibold_21.c +++ b/core/embed/lib/fonts/font_tthoves_demibold_21.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_tthoves_demibold_21.h b/core/embed/lib/fonts/font_tthoves_demibold_21.h index 2cc9ab3ca7..bcaf664609 100644 --- a/core/embed/lib/fonts/font_tthoves_demibold_21.h +++ b/core/embed/lib/fonts/font_tthoves_demibold_21.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_tthoves_regular_21.c b/core/embed/lib/fonts/font_tthoves_regular_21.c index aceee17872..2db8aae33c 100644 --- a/core/embed/lib/fonts/font_tthoves_regular_21.c +++ b/core/embed/lib/fonts/font_tthoves_regular_21.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_tthoves_regular_21.h b/core/embed/lib/fonts/font_tthoves_regular_21.h index 7d1eafe2fb..82e48105fe 100644 --- a/core/embed/lib/fonts/font_tthoves_regular_21.h +++ b/core/embed/lib/fonts/font_tthoves_regular_21.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_18.c b/core/embed/lib/fonts/font_ttsatoshi_demibold_18.c index c1e481a39e..f46c501dab 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_18.c +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_18.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -6,6 +8,8 @@ // - the third, fourth and fifth bytes are advance, bearingX and bearingY of the horizontal metrics of the glyph // - the rest is packed 4-bit glyph data +// NOTE: numeral chars ('0','1',..,'9') mapped to alternative style glyphs contained in the font (glyph indices: 1298-1307) + /* */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_32[] = { 0, 0, 5, 0, 0 }; /* ! */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_33[] = { 3, 13, 5, 1, 13, 248, 12, 248, 12, 248, 12, 248, 12, 248, 12, 248, 11, 247, 10, 245, 8, 244, 7, 64, 1, 132, 6, 248, 12, 248, 12 }; /* " */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_34[] = { 6, 5, 8, 1, 13, 254, 146, 127, 254, 146, 127, 254, 146, 127, 254, 146, 127, 34, 16, 18 }; @@ -22,15 +26,15 @@ /* - */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_45[] = { 7, 3, 8, 0, 7, 0, 0, 0, 0, 243, 255, 255, 14, 243, 255, 255, 14 }; /* . */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_46[] = { 3, 3, 5, 1, 3, 135, 4, 254, 9, 254, 9 }; /* / */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_47[] = { 8, 17, 7, 0, 13, 0, 0, 178, 11, 0, 0, 246, 13, 0, 0, 251, 8, 0, 0, 255, 3, 0, 80, 239, 0, 0, 144, 175, 0, 0, 224, 95, 0, 0, 243, 31, 0, 0, 247, 12, 0, 0, 252, 7, 0, 16, 255, 2, 0, 96, 223, 0, 0, 160, 159, 0, 0, 240, 79, 0, 0, 244, 15, 0, 0, 248, 11, 0, 0, 253, 6, 0, 0 }; -/* 0 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_48[] = { 12, 13, 12, 0, 13, 0, 48, 234, 174, 3, 0, 0, 246, 255, 255, 127, 0, 32, 255, 109, 198, 255, 2, 160, 239, 0, 0, 253, 11, 224, 127, 0, 0, 246, 15, 240, 79, 0, 0, 243, 31, 242, 47, 0, 0, 242, 63, 240, 79, 0, 0, 243, 31, 224, 127, 0, 0, 246, 15, 160, 239, 0, 0, 253, 11, 32, 255, 93, 197, 255, 2, 0, 246, 255, 255, 127, 0, 0, 48, 234, 190, 4, 0 }; -/* 1 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_49[] = { 6, 13, 7, 0, 13, 0, 240, 111, 248, 255, 111, 248, 255, 111, 66, 244, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111, 0, 240, 111 }; -/* 2 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_50[] = { 10, 13, 10, 0, 13, 0, 162, 238, 76, 0, 32, 255, 255, 255, 6, 192, 255, 86, 253, 15, 240, 111, 0, 244, 63, 113, 23, 0, 242, 79, 0, 0, 0, 249, 31, 0, 0, 128, 255, 7, 0, 0, 248, 143, 0, 0, 128, 255, 9, 0, 0, 248, 159, 0, 0, 144, 255, 76, 51, 35, 240, 255, 255, 255, 143, 240, 255, 255, 255, 143 }; -/* 3 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_51[] = { 10, 13, 10, 0, 13, 0, 179, 238, 92, 0, 96, 255, 255, 255, 7, 240, 207, 102, 252, 15, 162, 26, 0, 243, 63, 0, 0, 16, 249, 15, 0, 0, 253, 255, 5, 0, 0, 253, 239, 4, 0, 0, 33, 250, 30, 16, 1, 0, 240, 79, 245, 31, 0, 240, 95, 242, 207, 85, 251, 47, 112, 255, 255, 255, 8, 0, 196, 238, 92, 0 }; -/* 4 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_52[] = { 10, 13, 10, 0, 13, 0, 0, 248, 255, 5, 0, 16, 255, 255, 5, 0, 144, 239, 255, 5, 0, 242, 79, 255, 5, 0, 251, 11, 255, 5, 64, 255, 3, 255, 5, 192, 175, 0, 255, 5, 245, 47, 0, 255, 5, 251, 255, 255, 255, 207, 251, 255, 255, 255, 207, 34, 34, 34, 255, 39, 0, 0, 0, 255, 5, 0, 0, 0, 255, 5 }; -/* 5 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_53[] = { 10, 13, 11, 0, 13, 80, 255, 255, 255, 31, 96, 255, 255, 255, 31, 128, 207, 68, 68, 4, 144, 175, 0, 0, 0, 176, 159, 16, 0, 0, 192, 239, 255, 175, 1, 224, 255, 255, 255, 30, 128, 120, 2, 245, 143, 0, 0, 0, 144, 191, 145, 57, 0, 160, 175, 224, 239, 86, 250, 111, 64, 255, 255, 255, 11, 0, 162, 253, 124, 0 }; +/* 0 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_48[] = { 11, 13, 10, 0, 13, 0, 145, 237, 91, 0, 0, 64, 254, 255, 255, 9, 0, 224, 239, 87, 251, 95, 0, 247, 47, 0, 176, 223, 0, 251, 10, 0, 48, 255, 2, 253, 7, 0, 0, 255, 4, 255, 5, 0, 0, 255, 6, 253, 7, 0, 0, 255, 4, 251, 10, 0, 48, 255, 2, 247, 47, 0, 176, 239, 0, 224, 239, 86, 251, 95, 0, 64, 254, 255, 255, 9, 0, 0, 162, 237, 91, 0, 0 }; +/* 1 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_49[] = { 9, 13, 10, 1, 13, 0, 224, 127, 0, 0, 253, 255, 127, 0, 0, 253, 255, 127, 0, 0, 67, 228, 127, 0, 0, 0, 208, 127, 0, 0, 0, 208, 127, 0, 0, 0, 208, 127, 0, 0, 0, 208, 127, 0, 0, 0, 208, 127, 0, 0, 0, 208, 127, 0, 0, 84, 229, 175, 85, 2, 253, 255, 255, 255, 8, 253, 255, 255, 255, 8 }; +/* 2 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_50[] = { 10, 13, 10, 0, 13, 0, 145, 253, 92, 0, 16, 254, 255, 255, 8, 160, 255, 87, 252, 31, 224, 127, 0, 243, 95, 112, 39, 0, 241, 111, 0, 0, 0, 248, 47, 0, 0, 112, 255, 8, 0, 0, 247, 175, 0, 0, 112, 255, 10, 0, 0, 247, 175, 0, 0, 112, 255, 77, 51, 35, 224, 255, 255, 255, 159, 224, 255, 255, 255, 159 }; +/* 3 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_51[] = { 10, 13, 10, 0, 13, 0, 162, 253, 108, 0, 48, 255, 255, 255, 10, 208, 223, 87, 250, 63, 160, 58, 0, 240, 111, 0, 0, 0, 247, 63, 0, 0, 250, 255, 7, 0, 0, 250, 255, 6, 0, 0, 32, 248, 63, 16, 1, 0, 208, 127, 242, 63, 0, 208, 143, 224, 223, 70, 250, 95, 80, 255, 255, 255, 11, 0, 179, 254, 108, 0 }; +/* 4 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_52[] = { 11, 13, 10, 0, 13, 0, 0, 243, 255, 10, 0, 0, 0, 252, 255, 10, 0, 0, 80, 255, 255, 10, 0, 0, 208, 143, 251, 10, 0, 0, 247, 30, 251, 10, 0, 16, 254, 7, 251, 10, 0, 128, 239, 0, 251, 10, 0, 241, 95, 0, 251, 10, 0, 247, 255, 255, 255, 255, 1, 247, 255, 255, 255, 255, 1, 33, 34, 34, 252, 43, 0, 0, 0, 0, 251, 10, 0, 0, 0, 0, 251, 10, 0 }; +/* 5 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_53[] = { 10, 13, 10, 0, 13, 96, 255, 255, 255, 15, 112, 255, 255, 255, 15, 144, 191, 68, 68, 4, 160, 159, 0, 0, 0, 192, 127, 16, 0, 0, 224, 239, 255, 175, 1, 240, 255, 255, 255, 13, 128, 104, 2, 246, 127, 0, 0, 0, 176, 175, 146, 41, 0, 192, 159, 240, 223, 85, 250, 79, 80, 255, 255, 255, 10, 0, 179, 254, 108, 0 }; /* 6 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_54[] = { 10, 13, 10, 0, 13, 0, 0, 243, 127, 0, 0, 0, 253, 13, 0, 0, 128, 255, 3, 0, 0, 243, 143, 0, 0, 0, 253, 255, 108, 0, 112, 255, 255, 255, 9, 224, 239, 53, 250, 63, 243, 79, 0, 208, 143, 243, 31, 0, 160, 175, 241, 79, 0, 208, 143, 192, 239, 53, 250, 63, 32, 255, 255, 255, 9, 0, 161, 253, 92, 0 }; -/* 7 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_55[] = { 9, 13, 9, 0, 13, 248, 255, 255, 255, 14, 248, 255, 255, 255, 14, 66, 68, 68, 255, 11, 0, 0, 64, 255, 5, 0, 0, 176, 239, 0, 0, 0, 241, 143, 0, 0, 0, 248, 47, 0, 0, 0, 254, 11, 0, 0, 64, 255, 5, 0, 0, 176, 239, 0, 0, 0, 242, 143, 0, 0, 0, 248, 31, 0, 0, 0, 254, 11, 0, 0 }; -/* 8 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_56[] = { 10, 13, 11, 0, 13, 0, 162, 253, 124, 0, 32, 255, 255, 255, 11, 176, 223, 37, 248, 79, 208, 127, 0, 208, 127, 160, 207, 3, 246, 79, 16, 252, 255, 255, 8, 32, 253, 255, 255, 9, 192, 207, 2, 245, 95, 241, 63, 0, 160, 175, 242, 79, 0, 160, 191, 224, 223, 19, 246, 143, 64, 255, 255, 255, 13, 0, 162, 253, 140, 0 }; +/* 7 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_55[] = { 10, 13, 10, 0, 13, 240, 255, 255, 255, 111, 240, 255, 255, 255, 111, 64, 68, 68, 248, 79, 0, 0, 0, 251, 13, 0, 0, 32, 255, 7, 0, 0, 128, 255, 1, 0, 0, 224, 175, 0, 0, 0, 245, 63, 0, 0, 0, 252, 13, 0, 0, 32, 255, 7, 0, 0, 144, 255, 1, 0, 0, 224, 175, 0, 0, 0, 246, 63, 0, 0 }; +/* 8 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_56[] = { 10, 13, 10, 0, 13, 0, 162, 254, 108, 0, 48, 255, 255, 255, 10, 192, 223, 36, 248, 63, 240, 111, 0, 240, 111, 176, 207, 19, 247, 47, 32, 253, 255, 255, 6, 32, 253, 255, 255, 7, 208, 191, 2, 246, 79, 242, 47, 0, 176, 159, 243, 47, 0, 176, 175, 240, 207, 19, 247, 111, 80, 255, 255, 255, 12, 0, 179, 254, 124, 0 }; /* 9 */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_57[] = { 10, 13, 10, 0, 13, 0, 161, 237, 92, 0, 32, 255, 255, 255, 8, 192, 239, 53, 250, 63, 241, 79, 0, 208, 143, 243, 31, 0, 160, 175, 241, 79, 0, 208, 175, 192, 239, 53, 250, 111, 48, 255, 255, 255, 14, 0, 162, 254, 255, 4, 0, 0, 242, 159, 0, 0, 0, 252, 14, 0, 0, 96, 255, 4, 0, 0, 241, 175, 0, 0 }; /* : */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_58[] = { 3, 10, 5, 1, 10, 254, 9, 254, 9, 135, 5, 0, 0, 0, 0, 0, 0, 0, 0, 135, 4, 254, 9, 254, 9 }; /* ; */ static const uint8_t Font_TTSatoshi_DemiBold_18_glyph_59[] = { 4, 12, 5, 0, 10, 208, 175, 208, 175, 112, 88, 0, 0, 0, 0, 0, 0, 0, 0, 224, 143, 240, 79, 241, 15, 243, 11, 32, 1 }; diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_18.h b/core/embed/lib/fonts/font_ttsatoshi_demibold_18.h index 38da0fa2d4..0508e3a324 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_18.h +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_18.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_21.c b/core/embed/lib/fonts/font_ttsatoshi_demibold_21.c index 2a3079b125..edd6f21f3e 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_21.c +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_21.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -6,6 +8,8 @@ // - the third, fourth and fifth bytes are advance, bearingX and bearingY of the horizontal metrics of the glyph // - the rest is packed 4-bit glyph data +// NOTE: numeral chars ('0','1',..,'9') mapped to alternative style glyphs contained in the font (glyph indices: 1298-1307) +// /* */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_32[] = { 0, 0, 5, 0, 0 }; /* ! */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_33[] = { 4, 15, 6, 1, 15, 245, 111, 245, 111, 245, 111, 245, 111, 245, 111, 245, 111, 244, 95, 243, 79, 241, 47, 240, 31, 160, 10, 0, 0, 228, 110, 245, 111, 245, 111 }; /* " */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_34[] = { 7, 5, 9, 1, 15, 251, 10, 253, 8, 251, 10, 253, 8, 251, 10, 253, 8, 251, 10, 253, 8, 218, 9, 219, 7 }; @@ -22,15 +26,15 @@ /* - */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_45[] = { 9, 3, 9, 0, 8, 96, 102, 102, 102, 0, 240, 255, 255, 255, 1, 240, 255, 255, 255, 1 }; /* . */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_46[] = { 4, 3, 5, 1, 3, 235, 46, 251, 47, 251, 47 }; /* / */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_47[] = { 9, 20, 8, 0, 16, 0, 0, 32, 136, 2, 0, 0, 128, 255, 1, 0, 0, 208, 207, 0, 0, 0, 242, 127, 0, 0, 0, 246, 63, 0, 0, 0, 251, 14, 0, 0, 0, 255, 9, 0, 0, 64, 255, 4, 0, 0, 144, 255, 0, 0, 0, 224, 191, 0, 0, 0, 243, 111, 0, 0, 0, 247, 47, 0, 0, 0, 252, 13, 0, 0, 16, 255, 8, 0, 0, 96, 255, 3, 0, 0, 160, 239, 0, 0, 0, 240, 175, 0, 0, 0, 244, 95, 0, 0, 0, 248, 31, 0, 0, 0, 253, 12, 0, 0, 0 }; -/* 0 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_48[] = { 14, 15, 14, 0, 15, 0, 0, 197, 255, 108, 0, 0, 0, 144, 255, 255, 255, 10, 0, 0, 249, 255, 187, 255, 159, 0, 32, 255, 46, 0, 210, 255, 2, 144, 255, 5, 0, 64, 255, 10, 192, 239, 0, 0, 0, 254, 12, 224, 207, 0, 0, 0, 251, 15, 240, 191, 0, 0, 0, 250, 31, 224, 207, 0, 0, 0, 251, 15, 192, 239, 0, 0, 0, 254, 12, 144, 255, 5, 0, 64, 255, 10, 32, 255, 46, 0, 210, 255, 3, 0, 249, 255, 187, 255, 175, 0, 0, 160, 255, 255, 255, 10, 0, 0, 0, 165, 238, 107, 0, 0 }; -/* 1 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_49[] = { 7, 15, 8, 0, 15, 0, 112, 255, 4, 148, 217, 255, 4, 247, 255, 255, 4, 247, 255, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4, 0, 96, 255, 4 }; -/* 2 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_50[] = { 12, 15, 12, 0, 15, 0, 80, 235, 190, 5, 0, 0, 249, 255, 255, 159, 0, 80, 255, 191, 251, 255, 5, 192, 255, 4, 96, 255, 10, 240, 207, 0, 0, 255, 13, 32, 18, 0, 16, 255, 12, 0, 0, 0, 160, 255, 7, 0, 0, 0, 249, 207, 0, 0, 0, 160, 255, 29, 0, 0, 0, 250, 223, 1, 0, 0, 160, 255, 29, 0, 0, 0, 251, 223, 1, 0, 0, 160, 255, 191, 153, 153, 25, 208, 255, 255, 255, 255, 31, 208, 255, 255, 255, 255, 31 }; -/* 3 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_51[] = { 12, 15, 12, 0, 15, 0, 112, 236, 190, 5, 0, 16, 253, 255, 255, 175, 0, 160, 255, 174, 251, 255, 5, 240, 223, 0, 48, 255, 10, 80, 53, 0, 0, 255, 11, 0, 0, 0, 145, 255, 7, 0, 0, 242, 255, 191, 0, 0, 0, 242, 255, 95, 0, 0, 0, 97, 232, 255, 4, 0, 0, 0, 16, 254, 12, 163, 74, 0, 0, 252, 15, 242, 207, 0, 32, 255, 13, 192, 255, 174, 251, 255, 8, 32, 254, 255, 255, 191, 0, 0, 128, 252, 190, 5, 0 }; -/* 4 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_52[] = { 12, 15, 12, 0, 15, 0, 0, 176, 255, 191, 0, 0, 0, 244, 255, 191, 0, 0, 0, 252, 255, 191, 0, 0, 80, 255, 249, 191, 0, 0, 208, 239, 240, 191, 0, 0, 246, 111, 240, 191, 0, 0, 254, 13, 240, 191, 0, 112, 255, 5, 240, 191, 0, 241, 223, 0, 240, 191, 0, 248, 191, 136, 248, 239, 56, 250, 255, 255, 255, 255, 111, 250, 255, 255, 255, 255, 111, 0, 0, 0, 240, 191, 0, 0, 0, 0, 240, 191, 0, 0, 0, 0, 240, 191, 0 }; -/* 5 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_53[] = { 12, 15, 12, 0, 15, 0, 255, 255, 255, 255, 9, 16, 255, 255, 255, 255, 9, 48, 255, 156, 153, 153, 5, 64, 255, 5, 0, 0, 0, 96, 255, 3, 0, 0, 0, 112, 255, 100, 87, 1, 0, 144, 255, 255, 255, 127, 0, 160, 255, 255, 255, 255, 7, 176, 255, 40, 80, 255, 31, 0, 0, 0, 0, 247, 79, 48, 35, 0, 0, 245, 95, 224, 239, 2, 0, 251, 47, 112, 255, 191, 234, 255, 11, 0, 251, 255, 255, 223, 1, 0, 96, 235, 207, 8, 0 }; +/* 0 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_48[] = { 13, 15, 12, 0, 15, 0, 80, 236, 207, 6, 0, 0, 0, 249, 255, 255, 191, 1, 0, 128, 255, 207, 251, 255, 10, 0, 241, 239, 3, 32, 253, 63, 0, 248, 111, 0, 0, 243, 191, 0, 251, 15, 0, 0, 208, 223, 0, 253, 13, 0, 0, 176, 255, 0, 255, 11, 0, 0, 144, 255, 2, 253, 13, 0, 0, 176, 255, 0, 251, 15, 0, 0, 208, 223, 0, 248, 111, 0, 0, 243, 191, 0, 241, 239, 3, 16, 253, 63, 0, 128, 255, 191, 251, 255, 10, 0, 0, 249, 255, 255, 191, 1, 0, 0, 80, 234, 190, 6, 0, 0 }; +/* 1 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_49[] = { 11, 15, 12, 1, 15, 0, 32, 255, 8, 0, 0, 150, 201, 255, 8, 0, 0, 250, 255, 255, 8, 0, 0, 250, 255, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 0, 32, 255, 8, 0, 0, 183, 203, 255, 189, 187, 1, 250, 255, 255, 255, 255, 1, 250, 255, 255, 255, 255, 1 }; +/* 2 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_50[] = { 11, 15, 12, 1, 15, 0, 180, 238, 108, 0, 0, 128, 255, 255, 255, 11, 0, 243, 255, 188, 255, 111, 0, 250, 111, 0, 244, 207, 0, 253, 14, 0, 208, 255, 0, 34, 2, 0, 240, 239, 0, 0, 0, 0, 248, 159, 0, 0, 0, 128, 255, 29, 0, 0, 0, 248, 239, 2, 0, 0, 144, 255, 46, 0, 0, 0, 249, 239, 2, 0, 0, 144, 255, 46, 0, 0, 0, 249, 255, 155, 153, 153, 2, 251, 255, 255, 255, 255, 3, 251, 255, 255, 255, 255, 3 }; +/* 3 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_51[] = { 12, 15, 12, 0, 15, 0, 80, 235, 207, 7, 0, 0, 250, 255, 255, 223, 0, 112, 255, 191, 234, 255, 9, 192, 255, 2, 16, 254, 13, 64, 69, 0, 0, 252, 15, 0, 0, 0, 97, 255, 10, 0, 0, 240, 255, 223, 1, 0, 0, 240, 255, 127, 0, 0, 0, 96, 199, 255, 7, 0, 0, 0, 0, 252, 15, 161, 106, 0, 0, 248, 47, 240, 239, 2, 0, 253, 15, 144, 255, 191, 234, 255, 11, 0, 252, 255, 255, 223, 1, 0, 96, 235, 206, 7, 0 }; +/* 4 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_52[] = { 12, 15, 12, 0, 15, 0, 0, 96, 255, 255, 1, 0, 0, 224, 255, 255, 1, 0, 0, 247, 255, 255, 1, 0, 16, 255, 188, 255, 1, 0, 128, 255, 164, 255, 1, 0, 242, 191, 160, 255, 1, 0, 250, 63, 160, 255, 1, 48, 255, 10, 160, 255, 1, 176, 255, 2, 160, 255, 1, 243, 239, 136, 216, 255, 104, 245, 255, 255, 255, 255, 191, 245, 255, 255, 255, 255, 191, 0, 0, 0, 160, 255, 1, 0, 0, 0, 160, 255, 1, 0, 0, 0, 160, 255, 1 }; +/* 5 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_53[] = { 12, 15, 12, 0, 15, 32, 255, 255, 255, 255, 7, 48, 255, 255, 255, 255, 7, 80, 255, 155, 153, 153, 4, 96, 255, 3, 0, 0, 0, 128, 255, 1, 0, 0, 0, 144, 255, 99, 71, 1, 0, 176, 255, 255, 255, 111, 0, 192, 255, 255, 255, 255, 5, 208, 255, 39, 97, 255, 15, 0, 0, 0, 0, 249, 63, 48, 35, 0, 0, 247, 79, 240, 239, 1, 0, 253, 31, 144, 255, 191, 234, 255, 10, 0, 252, 255, 255, 223, 1, 0, 112, 235, 206, 7, 0 }; /* 6 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_54[] = { 12, 15, 12, 0, 15, 0, 0, 80, 255, 12, 0, 0, 0, 225, 255, 3, 0, 0, 0, 249, 159, 0, 0, 0, 48, 255, 30, 0, 0, 0, 208, 255, 6, 0, 0, 0, 247, 255, 207, 7, 0, 32, 255, 255, 255, 207, 0, 160, 255, 175, 233, 255, 9, 240, 255, 2, 16, 254, 15, 242, 175, 0, 0, 248, 63, 241, 175, 0, 0, 248, 63, 224, 255, 2, 16, 253, 15, 96, 255, 159, 233, 255, 8, 0, 250, 255, 255, 207, 0, 0, 80, 235, 190, 6, 0 }; -/* 7 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_55[] = { 11, 15, 11, 0, 15, 247, 255, 255, 255, 255, 6, 247, 255, 255, 255, 255, 6, 148, 153, 153, 249, 255, 5, 0, 0, 0, 242, 239, 0, 0, 0, 0, 248, 143, 0, 0, 0, 0, 254, 47, 0, 0, 0, 80, 255, 11, 0, 0, 0, 176, 255, 4, 0, 0, 0, 242, 239, 0, 0, 0, 0, 248, 127, 0, 0, 0, 0, 254, 31, 0, 0, 0, 80, 255, 10, 0, 0, 0, 192, 255, 4, 0, 0, 0, 242, 223, 0, 0, 0, 0, 249, 111, 0, 0, 0 }; -/* 8 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_56[] = { 12, 15, 12, 0, 15, 0, 64, 235, 207, 8, 0, 0, 249, 255, 255, 239, 1, 80, 255, 142, 199, 255, 11, 144, 255, 3, 0, 253, 15, 160, 255, 0, 0, 250, 15, 96, 255, 26, 80, 255, 11, 0, 249, 255, 255, 223, 2, 0, 246, 255, 255, 191, 0, 80, 255, 109, 165, 255, 11, 208, 239, 0, 0, 249, 47, 240, 191, 0, 0, 245, 111, 224, 239, 1, 0, 250, 79, 128, 255, 142, 183, 255, 14, 0, 252, 255, 255, 239, 3, 0, 80, 235, 207, 24, 0 }; +/* 7 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_55[] = { 11, 15, 12, 1, 15, 253, 255, 255, 255, 255, 0, 253, 255, 255, 255, 255, 0, 152, 153, 153, 251, 255, 0, 0, 0, 0, 247, 159, 0, 0, 0, 0, 254, 47, 0, 0, 0, 64, 255, 12, 0, 0, 0, 176, 255, 5, 0, 0, 0, 242, 239, 0, 0, 0, 0, 248, 143, 0, 0, 0, 0, 254, 47, 0, 0, 0, 80, 255, 11, 0, 0, 0, 176, 255, 4, 0, 0, 0, 242, 239, 0, 0, 0, 0, 248, 127, 0, 0, 0, 0, 254, 31, 0, 0, 0 }; +/* 8 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_56[] = { 12, 15, 12, 0, 15, 0, 80, 235, 206, 7, 0, 0, 251, 255, 255, 223, 0, 96, 255, 142, 215, 255, 9, 176, 255, 1, 0, 254, 14, 192, 255, 0, 0, 252, 14, 112, 255, 25, 112, 255, 10, 0, 251, 255, 255, 207, 1, 0, 247, 255, 255, 159, 0, 112, 255, 108, 182, 255, 9, 224, 223, 0, 0, 251, 31, 241, 159, 0, 0, 247, 79, 240, 223, 0, 0, 251, 47, 160, 255, 125, 199, 255, 12, 16, 253, 255, 255, 239, 2, 0, 96, 236, 206, 8, 0 }; /* 9 */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_57[] = { 12, 15, 12, 0, 15, 0, 64, 235, 190, 6, 0, 0, 250, 255, 255, 191, 0, 96, 255, 175, 233, 255, 8, 208, 255, 2, 16, 254, 15, 241, 175, 0, 0, 248, 63, 241, 175, 0, 0, 248, 79, 224, 255, 2, 16, 253, 47, 96, 255, 159, 233, 255, 12, 0, 250, 255, 255, 255, 4, 0, 80, 235, 255, 175, 0, 0, 0, 48, 255, 30, 0, 0, 0, 208, 255, 6, 0, 0, 0, 247, 207, 0, 0, 0, 16, 255, 47, 0, 0, 0, 160, 255, 8, 0, 0 }; /* : */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_58[] = { 4, 11, 5, 1, 11, 251, 47, 251, 47, 251, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 235, 46, 251, 47, 251, 47 }; /* ; */ static const uint8_t Font_TTSatoshi_DemiBold_21_glyph_59[] = { 5, 13, 5, 0, 11, 160, 255, 4, 160, 255, 4, 144, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 2, 192, 223, 0, 224, 159, 0, 240, 79, 0, 209, 13, 0 }; diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_21.h b/core/embed/lib/fonts/font_ttsatoshi_demibold_21.h index e995c54edd..79c7b42403 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_21.h +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_21.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_42.c b/core/embed/lib/fonts/font_ttsatoshi_demibold_42.c index 8c06d83a9f..20bc5b8f8f 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_42.c +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_42.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off @@ -7,70 +9,6 @@ // - the rest is packed 4-bit glyph data /* */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_32[] = { 0, 0, 11, 0, 0 }; -/* ! */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_33[] = { 6, 29, 12, 3, 29, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 249, 255, 207, 248, 255, 191, 247, 255, 159, 245, 255, 143, 244, 255, 111, 242, 255, 95, 241, 255, 63, 240, 255, 47, 224, 255, 15, 80, 102, 6, 0, 0, 0, 0, 0, 0, 216, 221, 189, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207, 250, 255, 207 }; -/* " */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_34[] = { 14, 10, 18, 2, 29, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 247, 255, 95, 0, 251, 255, 31, 165, 170, 58, 0, 167, 170, 26 }; -/* # */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_35[] = { 30, 29, 30, 0, 29, 0, 0, 0, 0, 0, 246, 255, 111, 0, 0, 245, 255, 127, 0, 0, 0, 0, 0, 0, 0, 249, 255, 63, 0, 0, 248, 255, 79, 0, 0, 0, 0, 0, 0, 0, 253, 255, 15, 0, 0, 252, 255, 31, 0, 0, 0, 0, 0, 0, 0, 255, 255, 12, 0, 0, 255, 255, 13, 0, 0, 0, 0, 0, 0, 48, 255, 255, 8, 0, 48, 255, 255, 10, 0, 0, 0, 0, 0, 0, 112, 255, 255, 5, 0, 96, 255, 255, 6, 0, 0, 0, 0, 0, 0, 160, 255, 255, 1, 0, 160, 255, 255, 3, 0, 0, 0, 80, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 144, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 79, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 146, 153, 153, 255, 255, 175, 153, 153, 254, 255, 175, 153, 153, 6, 0, 0, 0, 0, 255, 255, 13, 0, 0, 254, 255, 14, 0, 0, 0, 0, 0, 0, 48, 255, 255, 9, 0, 32, 255, 255, 10, 0, 0, 0, 0, 0, 0, 112, 255, 255, 6, 0, 80, 255, 255, 7, 0, 0, 0, 0, 0, 0, 160, 255, 255, 2, 0, 144, 255, 255, 4, 0, 0, 0, 0, 0, 0, 224, 255, 239, 0, 0, 192, 255, 255, 0, 0, 0, 0, 80, 153, 153, 249, 255, 239, 153, 153, 249, 255, 255, 153, 153, 41, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 243, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 247, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 32, 255, 255, 10, 0, 16, 255, 255, 11, 0, 0, 0, 0, 0, 0, 96, 255, 255, 6, 0, 64, 255, 255, 8, 0, 0, 0, 0, 0, 0, 144, 255, 255, 3, 0, 128, 255, 255, 4, 0, 0, 0, 0, 0, 0, 208, 255, 255, 0, 0, 176, 255, 255, 1, 0, 0, 0, 0, 0, 0, 240, 255, 207, 0, 0, 240, 255, 223, 0, 0, 0, 0, 0, 0, 0, 244, 255, 143, 0, 0, 242, 255, 175, 0, 0, 0, 0, 0, 0, 0, 247, 255, 95, 0, 0, 246, 255, 111, 0, 0, 0, 0, 0 }; -/* $ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_36[] = { 24, 40, 27, 1, 35, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 97, 251, 255, 255, 207, 40, 0, 0, 0, 0, 0, 160, 255, 255, 255, 255, 255, 255, 43, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 242, 255, 255, 255, 255, 255, 255, 255, 255, 95, 0, 0, 252, 255, 255, 175, 87, 117, 250, 255, 255, 255, 1, 64, 255, 255, 207, 2, 0, 0, 32, 252, 255, 255, 9, 144, 255, 255, 31, 0, 0, 0, 0, 225, 255, 255, 15, 192, 255, 255, 11, 0, 0, 0, 0, 112, 255, 255, 63, 224, 255, 255, 9, 0, 0, 0, 0, 48, 255, 255, 79, 192, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 108, 2, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 239, 139, 37, 0, 0, 0, 0, 0, 245, 255, 255, 255, 255, 255, 255, 174, 4, 0, 0, 0, 80, 255, 255, 255, 255, 255, 255, 255, 207, 3, 0, 0, 0, 162, 255, 255, 255, 255, 255, 255, 255, 111, 0, 0, 0, 0, 64, 201, 254, 255, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 16, 116, 251, 255, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 143, 148, 153, 153, 0, 0, 0, 0, 0, 0, 253, 255, 191, 247, 255, 255, 3, 0, 0, 0, 0, 0, 252, 255, 207, 244, 255, 255, 10, 0, 0, 0, 0, 0, 255, 255, 191, 240, 255, 255, 159, 0, 0, 0, 0, 176, 255, 255, 159, 144, 255, 255, 255, 126, 20, 16, 115, 254, 255, 255, 95, 32, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 0, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 8, 0, 80, 255, 255, 255, 255, 255, 255, 255, 255, 207, 0, 0, 0, 178, 255, 255, 255, 255, 255, 255, 255, 28, 0, 0, 0, 0, 97, 251, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 176, 255, 255, 223, 90, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 32, 51, 51, 2, 0, 0, 0, 0 }; -/* % */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_37[] = { 32, 31, 34, 1, 30, 0, 0, 181, 254, 174, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 159, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 253, 255, 255, 255, 255, 11, 0, 0, 0, 96, 255, 255, 12, 0, 0, 128, 255, 255, 223, 255, 255, 95, 0, 0, 0, 241, 255, 255, 3, 0, 0, 241, 255, 143, 0, 177, 255, 239, 0, 0, 0, 251, 255, 143, 0, 0, 0, 245, 255, 12, 0, 16, 255, 255, 2, 0, 80, 255, 255, 14, 0, 0, 0, 247, 255, 8, 0, 0, 252, 255, 4, 0, 224, 255, 255, 4, 0, 0, 0, 247, 255, 8, 0, 0, 252, 255, 4, 0, 249, 255, 175, 0, 0, 0, 0, 245, 255, 12, 0, 16, 255, 255, 2, 48, 255, 255, 31, 0, 0, 0, 0, 241, 255, 143, 0, 177, 255, 239, 0, 208, 255, 255, 6, 0, 0, 0, 0, 144, 255, 255, 222, 255, 255, 95, 0, 247, 255, 207, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 11, 32, 255, 255, 47, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 159, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 181, 254, 174, 4, 0, 245, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 254, 255, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 239, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 95, 0, 48, 234, 239, 91, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 11, 0, 249, 255, 255, 255, 27, 0, 0, 0, 0, 0, 0, 242, 255, 255, 2, 160, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 245, 255, 255, 253, 255, 255, 8, 0, 0, 0, 0, 96, 255, 255, 13, 0, 253, 255, 27, 0, 248, 255, 31, 0, 0, 0, 0, 225, 255, 255, 3, 32, 255, 255, 1, 0, 192, 255, 95, 0, 0, 0, 0, 250, 255, 159, 0, 64, 255, 207, 0, 0, 128, 255, 127, 0, 0, 0, 64, 255, 255, 14, 0, 64, 255, 207, 0, 0, 128, 255, 143, 0, 0, 0, 208, 255, 255, 5, 0, 32, 255, 255, 1, 0, 192, 255, 111, 0, 0, 0, 248, 255, 191, 0, 0, 0, 254, 255, 27, 0, 248, 255, 31, 0, 0, 48, 255, 255, 31, 0, 0, 0, 245, 255, 255, 237, 255, 255, 9, 0, 0, 192, 255, 255, 7, 0, 0, 0, 176, 255, 255, 255, 255, 223, 0, 0, 0, 246, 255, 207, 0, 0, 0, 0, 0, 249, 255, 255, 255, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 234, 239, 91, 0, 0 }; -/* & */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_38[] = { 27, 31, 27, 1, 30, 0, 0, 0, 130, 236, 239, 140, 1, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 16, 253, 255, 255, 255, 255, 255, 29, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 255, 255, 255, 191, 0, 0, 0, 0, 0, 0, 244, 255, 255, 223, 202, 255, 255, 255, 4, 0, 0, 0, 0, 0, 249, 255, 255, 5, 0, 244, 255, 255, 10, 0, 0, 0, 0, 0, 252, 255, 175, 0, 0, 144, 255, 255, 13, 0, 0, 0, 0, 0, 253, 255, 127, 0, 0, 80, 255, 255, 14, 0, 0, 0, 0, 0, 251, 255, 159, 0, 0, 112, 255, 255, 12, 0, 0, 0, 0, 0, 248, 255, 239, 0, 0, 208, 255, 255, 9, 0, 0, 0, 0, 0, 242, 255, 255, 11, 16, 252, 255, 255, 3, 0, 0, 0, 0, 0, 112, 255, 255, 159, 211, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 255, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 191, 1, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 255, 239, 6, 0, 0, 0, 0, 0, 0, 0, 0, 210, 255, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 64, 254, 255, 255, 255, 255, 4, 0, 64, 238, 238, 11, 0, 0, 244, 255, 255, 255, 255, 255, 63, 0, 96, 255, 255, 9, 0, 32, 255, 255, 255, 156, 255, 255, 239, 2, 160, 255, 255, 7, 0, 160, 255, 255, 191, 0, 250, 255, 255, 30, 240, 255, 255, 4, 0, 240, 255, 255, 12, 0, 176, 255, 255, 223, 248, 255, 239, 0, 0, 242, 255, 255, 3, 0, 0, 252, 255, 255, 255, 255, 143, 0, 0, 244, 255, 255, 0, 0, 0, 209, 255, 255, 255, 255, 31, 0, 0, 244, 255, 255, 0, 0, 0, 32, 254, 255, 255, 255, 7, 0, 0, 243, 255, 255, 6, 0, 0, 0, 243, 255, 255, 239, 0, 0, 0, 224, 255, 255, 79, 0, 0, 16, 249, 255, 255, 255, 8, 0, 0, 128, 255, 255, 255, 140, 134, 251, 255, 255, 255, 255, 127, 0, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 6, 0, 0, 226, 255, 255, 255, 255, 255, 255, 143, 246, 255, 255, 95, 0, 0, 16, 250, 255, 255, 255, 255, 191, 2, 64, 254, 255, 255, 4, 0, 0, 16, 183, 254, 223, 138, 2, 0, 0, 0, 0, 0, 0 }; -/* ' */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_39[] = { 6, 10, 10, 2, 29, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 247, 255, 95, 165, 170, 58 }; -/* ( */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_40[] = { 13, 40, 15, 2, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 223, 0, 0, 0, 48, 255, 255, 79, 0, 0, 0, 192, 255, 255, 10, 0, 0, 0, 244, 255, 255, 2, 0, 0, 0, 252, 255, 159, 0, 0, 0, 48, 255, 255, 47, 0, 0, 0, 160, 255, 255, 11, 0, 0, 0, 240, 255, 255, 5, 0, 0, 0, 245, 255, 255, 0, 0, 0, 0, 250, 255, 175, 0, 0, 0, 0, 254, 255, 111, 0, 0, 0, 32, 255, 255, 47, 0, 0, 0, 96, 255, 255, 14, 0, 0, 0, 128, 255, 255, 11, 0, 0, 0, 176, 255, 255, 9, 0, 0, 0, 208, 255, 255, 6, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 3, 0, 0, 0, 240, 255, 255, 3, 0, 0, 0, 240, 255, 255, 3, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 208, 255, 255, 6, 0, 0, 0, 160, 255, 255, 9, 0, 0, 0, 128, 255, 255, 11, 0, 0, 0, 80, 255, 255, 14, 0, 0, 0, 32, 255, 255, 47, 0, 0, 0, 0, 254, 255, 111, 0, 0, 0, 0, 250, 255, 175, 0, 0, 0, 0, 245, 255, 255, 0, 0, 0, 0, 240, 255, 255, 5, 0, 0, 0, 144, 255, 255, 11, 0, 0, 0, 48, 255, 255, 47, 0, 0, 0, 0, 251, 255, 159, 0, 0, 0, 0, 244, 255, 255, 2, 0, 0, 0, 176, 255, 255, 10, 0, 0, 0, 32, 255, 255, 79, 0, 0, 0, 0, 248, 255, 239, 0 }; -/* ) */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_41[] = { 13, 40, 15, 0, 32, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 10, 0, 0, 0, 32, 255, 255, 79, 0, 0, 0, 0, 248, 255, 223, 0, 0, 0, 0, 241, 255, 255, 6, 0, 0, 0, 128, 255, 255, 13, 0, 0, 0, 16, 255, 255, 95, 0, 0, 0, 0, 249, 255, 191, 0, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 224, 255, 255, 7, 0, 0, 0, 128, 255, 255, 12, 0, 0, 0, 64, 255, 255, 15, 0, 0, 0, 0, 255, 255, 79, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 250, 255, 175, 0, 0, 0, 0, 247, 255, 207, 0, 0, 0, 0, 245, 255, 239, 0, 0, 0, 0, 243, 255, 255, 0, 0, 0, 0, 242, 255, 255, 1, 0, 0, 0, 242, 255, 255, 1, 0, 0, 0, 241, 255, 255, 2, 0, 0, 0, 242, 255, 255, 1, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 243, 255, 255, 0, 0, 0, 0, 245, 255, 239, 0, 0, 0, 0, 247, 255, 207, 0, 0, 0, 0, 250, 255, 175, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 255, 255, 63, 0, 0, 0, 64, 255, 255, 15, 0, 0, 0, 144, 255, 255, 11, 0, 0, 0, 224, 255, 255, 6, 0, 0, 0, 244, 255, 255, 1, 0, 0, 0, 250, 255, 191, 0, 0, 0, 16, 255, 255, 79, 0, 0, 0, 128, 255, 255, 13, 0, 0, 0, 241, 255, 255, 5, 0, 0, 0, 249, 255, 223, 0, 0, 0, 48, 255, 255, 79, 0, 0, 0, 208, 255, 255, 9, 0, 0, 0 }; -/* * */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_42[] = { 18, 17, 21, 1, 29, 0, 0, 0, 192, 255, 95, 0, 0, 0, 0, 0, 0, 176, 255, 79, 0, 0, 0, 0, 0, 0, 160, 255, 63, 0, 0, 0, 0, 0, 0, 144, 255, 47, 0, 0, 0, 32, 57, 0, 128, 255, 31, 0, 80, 8, 112, 255, 125, 113, 255, 15, 164, 255, 31, 192, 255, 255, 239, 255, 239, 255, 255, 95, 241, 255, 255, 255, 255, 255, 255, 255, 175, 97, 201, 255, 255, 255, 255, 255, 190, 71, 0, 0, 48, 252, 255, 255, 39, 0, 0, 0, 0, 80, 255, 255, 255, 13, 0, 0, 0, 0, 242, 255, 223, 255, 175, 0, 0, 0, 16, 253, 255, 42, 255, 255, 8, 0, 0, 176, 255, 239, 1, 246, 255, 95, 0, 0, 160, 255, 95, 0, 192, 255, 95, 0, 0, 0, 247, 10, 0, 32, 223, 2, 0, 0, 0, 64, 1, 0, 0, 4, 0, 0 }; -/* + */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_43[] = { 19, 21, 23, 2, 23, 0, 0, 0, 64, 102, 86, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 152, 153, 153, 233, 255, 255, 153, 153, 153, 9, 254, 255, 255, 255, 255, 255, 255, 255, 255, 15, 254, 255, 255, 255, 255, 255, 255, 255, 255, 15, 254, 255, 255, 255, 255, 255, 255, 255, 255, 15, 254, 255, 255, 255, 255, 255, 255, 255, 255, 15, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 192, 255, 223, 0, 0, 0, 0, 0, 0, 0, 144, 204, 172, 0, 0, 0, 0 }; -/* , */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_44[] = { 8, 10, 11, 1, 6, 80, 255, 255, 127, 112, 255, 255, 47, 128, 255, 255, 14, 160, 255, 255, 9, 192, 255, 255, 5, 224, 255, 255, 1, 240, 255, 207, 0, 241, 255, 127, 0, 243, 255, 63, 0, 163, 170, 10, 0 }; -/* - */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_45[] = { 16, 5, 18, 1, 15, 209, 221, 221, 221, 221, 221, 221, 45, 241, 255, 255, 255, 255, 255, 255, 47, 241, 255, 255, 255, 255, 255, 255, 47, 241, 255, 255, 255, 255, 255, 255, 47, 241, 255, 255, 255, 255, 255, 255, 47 }; -/* . */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_46[] = { 7, 6, 11, 2, 6, 214, 221, 221, 5, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6 }; -/* / */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_47[] = { 17, 40, 17, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 10, 0, 0, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 0, 0, 243, 255, 255, 0, 0, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 0, 16, 255, 255, 47, 0, 0, 0, 0, 0, 96, 255, 255, 13, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 0, 0, 244, 255, 255, 0, 0, 0, 0, 0, 0, 249, 255, 175, 0, 0, 0, 0, 0, 0, 253, 255, 111, 0, 0, 0, 0, 0, 32, 255, 255, 31, 0, 0, 0, 0, 0, 112, 255, 255, 12, 0, 0, 0, 0, 0, 192, 255, 255, 7, 0, 0, 0, 0, 0, 241, 255, 255, 3, 0, 0, 0, 0, 0, 245, 255, 239, 0, 0, 0, 0, 0, 0, 250, 255, 159, 0, 0, 0, 0, 0, 0, 254, 255, 79, 0, 0, 0, 0, 0, 48, 255, 255, 15, 0, 0, 0, 0, 0, 128, 255, 255, 11, 0, 0, 0, 0, 0, 208, 255, 255, 6, 0, 0, 0, 0, 0, 241, 255, 255, 2, 0, 0, 0, 0, 0, 246, 255, 223, 0, 0, 0, 0, 0, 0, 251, 255, 143, 0, 0, 0, 0, 0, 0, 255, 255, 63, 0, 0, 0, 0, 0, 64, 255, 255, 14, 0, 0, 0, 0, 0, 144, 255, 255, 10, 0, 0, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 0, 0, 247, 255, 207, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 0, 16, 255, 255, 47, 0, 0, 0, 0, 0, 80, 255, 255, 13, 0, 0, 0, 0, 0, 160, 255, 255, 9, 0, 0, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 0, 0, 244, 255, 255, 0, 0, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 0, 0, 253, 255, 111, 0, 0, 0, 0, 0, 0 }; -/* 0 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_48[] = { 26, 31, 28, 1, 30, 0, 0, 0, 0, 81, 219, 255, 189, 22, 0, 0, 0, 0, 0, 0, 0, 112, 255, 255, 255, 255, 255, 8, 0, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 239, 3, 0, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 62, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 239, 1, 0, 0, 144, 255, 255, 255, 142, 85, 215, 255, 255, 255, 11, 0, 0, 242, 255, 255, 159, 0, 0, 0, 248, 255, 255, 79, 0, 0, 249, 255, 255, 9, 0, 0, 0, 112, 255, 255, 191, 0, 0, 255, 255, 239, 0, 0, 0, 0, 0, 252, 255, 255, 2, 80, 255, 255, 111, 0, 0, 0, 0, 0, 244, 255, 255, 6, 128, 255, 255, 31, 0, 0, 0, 0, 0, 224, 255, 255, 10, 192, 255, 255, 12, 0, 0, 0, 0, 0, 160, 255, 255, 14, 224, 255, 255, 9, 0, 0, 0, 0, 0, 112, 255, 255, 15, 240, 255, 255, 7, 0, 0, 0, 0, 0, 80, 255, 255, 31, 240, 255, 255, 6, 0, 0, 0, 0, 0, 64, 255, 255, 47, 241, 255, 255, 5, 0, 0, 0, 0, 0, 48, 255, 255, 63, 240, 255, 255, 6, 0, 0, 0, 0, 0, 64, 255, 255, 47, 240, 255, 255, 7, 0, 0, 0, 0, 0, 80, 255, 255, 31, 224, 255, 255, 9, 0, 0, 0, 0, 0, 112, 255, 255, 15, 192, 255, 255, 12, 0, 0, 0, 0, 0, 160, 255, 255, 14, 128, 255, 255, 31, 0, 0, 0, 0, 0, 224, 255, 255, 10, 80, 255, 255, 111, 0, 0, 0, 0, 0, 244, 255, 255, 7, 16, 255, 255, 239, 0, 0, 0, 0, 0, 252, 255, 255, 2, 0, 249, 255, 255, 9, 0, 0, 0, 112, 255, 255, 191, 0, 0, 242, 255, 255, 159, 0, 0, 0, 247, 255, 255, 79, 0, 0, 144, 255, 255, 255, 142, 68, 215, 255, 255, 255, 11, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 239, 1, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 239, 3, 0, 0, 0, 0, 0, 112, 255, 255, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 97, 219, 255, 189, 22, 0, 0, 0, 0 }; -/* 1 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_49[] = { 12, 29, 16, 1, 29, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 48, 255, 255, 159, 255, 255, 255, 255, 255, 159, 255, 255, 255, 255, 255, 159, 255, 255, 255, 255, 255, 159, 255, 255, 255, 255, 255, 159, 255, 255, 255, 255, 255, 159, 68, 68, 68, 254, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159, 0, 0, 0, 253, 255, 159 }; -/* 2 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_50[] = { 22, 30, 24, 1, 30, 0, 0, 0, 97, 219, 255, 189, 23, 0, 0, 0, 0, 0, 128, 255, 255, 255, 255, 255, 9, 0, 0, 0, 16, 252, 255, 255, 255, 255, 255, 223, 1, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 12, 0, 0, 248, 255, 255, 255, 255, 255, 255, 255, 143, 0, 16, 255, 255, 255, 159, 85, 249, 255, 255, 255, 1, 112, 255, 255, 223, 2, 0, 32, 254, 255, 255, 6, 192, 255, 255, 63, 0, 0, 0, 245, 255, 255, 10, 240, 255, 255, 11, 0, 0, 0, 240, 255, 255, 12, 240, 255, 255, 7, 0, 0, 0, 208, 255, 255, 12, 80, 85, 85, 2, 0, 0, 0, 240, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 4, 0, 0, 0, 0, 0, 0, 176, 255, 255, 207, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 63, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 251, 255, 255, 111, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 252, 255, 255, 127, 0, 0, 0, 0, 0, 0, 193, 255, 255, 255, 7, 0, 0, 0, 0, 0, 16, 252, 255, 255, 111, 0, 0, 0, 0, 0, 0, 209, 255, 255, 255, 6, 0, 0, 0, 0, 0, 16, 253, 255, 255, 111, 0, 0, 0, 0, 0, 0, 209, 255, 255, 255, 5, 0, 0, 0, 0, 0, 32, 254, 255, 255, 159, 51, 51, 51, 51, 51, 3, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63 }; -/* 3 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_51[] = { 22, 31, 24, 1, 30, 0, 0, 0, 115, 236, 255, 189, 23, 0, 0, 0, 0, 0, 178, 255, 255, 255, 255, 255, 8, 0, 0, 0, 80, 255, 255, 255, 255, 255, 255, 223, 1, 0, 0, 245, 255, 255, 255, 255, 255, 255, 255, 12, 0, 16, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 128, 255, 255, 255, 123, 100, 232, 255, 255, 255, 0, 224, 255, 255, 79, 0, 0, 16, 252, 255, 255, 4, 242, 255, 255, 8, 0, 0, 0, 242, 255, 255, 7, 244, 255, 255, 4, 0, 0, 0, 224, 255, 255, 9, 32, 34, 34, 0, 0, 0, 0, 224, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 252, 255, 255, 2, 0, 0, 0, 0, 0, 32, 213, 255, 255, 191, 0, 0, 0, 0, 0, 245, 255, 255, 255, 255, 30, 0, 0, 0, 0, 0, 245, 255, 255, 255, 207, 2, 0, 0, 0, 0, 0, 245, 255, 255, 255, 29, 0, 0, 0, 0, 0, 0, 245, 255, 255, 255, 239, 4, 0, 0, 0, 0, 0, 212, 253, 255, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 130, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 13, 67, 68, 52, 0, 0, 0, 0, 128, 255, 255, 15, 250, 255, 239, 0, 0, 0, 0, 128, 255, 255, 15, 249, 255, 255, 4, 0, 0, 0, 208, 255, 255, 14, 244, 255, 255, 62, 0, 0, 0, 249, 255, 255, 11, 224, 255, 255, 255, 122, 84, 232, 255, 255, 255, 5, 96, 255, 255, 255, 255, 255, 255, 255, 255, 223, 0, 0, 250, 255, 255, 255, 255, 255, 255, 255, 46, 0, 0, 160, 255, 255, 255, 255, 255, 255, 239, 3, 0, 0, 0, 230, 255, 255, 255, 255, 255, 25, 0, 0, 0, 0, 0, 149, 236, 255, 189, 23, 0, 0, 0 }; -/* 4 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_52[] = { 23, 29, 24, 0, 29, 0, 0, 0, 0, 0, 242, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 247, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 16, 254, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 144, 255, 255, 143, 255, 255, 143, 0, 0, 0, 0, 0, 242, 255, 255, 10, 254, 255, 143, 0, 0, 0, 0, 0, 251, 255, 255, 1, 254, 255, 143, 0, 0, 0, 0, 64, 255, 255, 127, 0, 254, 255, 143, 0, 0, 0, 0, 208, 255, 255, 14, 0, 254, 255, 143, 0, 0, 0, 0, 246, 255, 255, 5, 0, 254, 255, 143, 0, 0, 0, 16, 254, 255, 207, 0, 0, 254, 255, 143, 0, 0, 0, 144, 255, 255, 63, 0, 0, 254, 255, 143, 0, 0, 0, 242, 255, 255, 9, 0, 0, 254, 255, 143, 0, 0, 0, 251, 255, 255, 1, 0, 0, 254, 255, 143, 0, 0, 64, 255, 255, 127, 0, 0, 0, 254, 255, 143, 0, 0, 208, 255, 255, 14, 0, 0, 0, 254, 255, 143, 0, 0, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 143, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 143, 0, 0 }; -/* 5 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_53[] = { 22, 30, 25, 1, 29, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 241, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 242, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 244, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 246, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 247, 255, 223, 68, 68, 68, 68, 68, 68, 0, 0, 249, 255, 175, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 95, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 95, 199, 254, 239, 107, 1, 0, 0, 16, 255, 255, 255, 255, 255, 255, 255, 126, 0, 0, 32, 255, 255, 255, 255, 255, 255, 255, 255, 10, 0, 64, 255, 255, 255, 255, 255, 255, 255, 255, 175, 0, 80, 255, 255, 255, 255, 255, 255, 255, 255, 255, 6, 112, 255, 255, 255, 75, 1, 99, 254, 255, 255, 14, 128, 238, 238, 94, 0, 0, 0, 209, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 207, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 223, 208, 221, 221, 6, 0, 0, 0, 0, 253, 255, 191, 224, 255, 255, 13, 0, 0, 0, 80, 255, 255, 143, 160, 255, 255, 191, 1, 0, 0, 227, 255, 255, 79, 64, 255, 255, 255, 158, 70, 166, 255, 255, 255, 13, 0, 251, 255, 255, 255, 255, 255, 255, 255, 255, 4, 0, 225, 255, 255, 255, 255, 255, 255, 255, 143, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 9, 0, 0, 0, 145, 255, 255, 255, 255, 255, 93, 0, 0, 0, 0, 0, 97, 219, 254, 206, 73, 0, 0, 0 }; -/* 6 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_54[] = { 22, 30, 24, 1, 29, 0, 0, 0, 0, 0, 245, 255, 255, 14, 0, 0, 0, 0, 0, 0, 16, 254, 255, 255, 5, 0, 0, 0, 0, 0, 0, 144, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 8, 0, 0, 0, 0, 0, 0, 128, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 252, 255, 255, 10, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 225, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 255, 223, 57, 0, 0, 0, 0, 64, 255, 255, 255, 255, 255, 255, 43, 0, 0, 0, 208, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 248, 255, 255, 255, 255, 255, 255, 255, 79, 0, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 128, 255, 255, 255, 76, 17, 147, 255, 255, 255, 9, 208, 255, 255, 143, 0, 0, 0, 243, 255, 255, 15, 241, 255, 255, 12, 0, 0, 0, 112, 255, 255, 95, 243, 255, 255, 6, 0, 0, 0, 16, 255, 255, 143, 244, 255, 255, 3, 0, 0, 0, 0, 253, 255, 159, 244, 255, 255, 3, 0, 0, 0, 0, 254, 255, 159, 242, 255, 255, 6, 0, 0, 0, 16, 255, 255, 143, 240, 255, 255, 13, 0, 0, 0, 112, 255, 255, 95, 160, 255, 255, 159, 0, 0, 0, 244, 255, 255, 15, 48, 255, 255, 255, 92, 18, 148, 255, 255, 255, 9, 0, 250, 255, 255, 255, 255, 255, 255, 255, 239, 1, 0, 208, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 16, 252, 255, 255, 255, 255, 255, 239, 4, 0, 0, 0, 112, 254, 255, 255, 255, 255, 26, 0, 0, 0, 0, 0, 96, 218, 255, 206, 39, 0, 0, 0 }; -/* 7 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_55[] = { 20, 29, 22, 1, 29, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 255, 207, 68, 68, 68, 68, 68, 68, 196, 255, 255, 127, 0, 0, 0, 0, 0, 0, 241, 255, 255, 31, 0, 0, 0, 0, 0, 0, 247, 255, 255, 10, 0, 0, 0, 0, 0, 0, 254, 255, 255, 3, 0, 0, 0, 0, 0, 80, 255, 255, 207, 0, 0, 0, 0, 0, 0, 176, 255, 255, 95, 0, 0, 0, 0, 0, 0, 242, 255, 255, 14, 0, 0, 0, 0, 0, 0, 249, 255, 255, 8, 0, 0, 0, 0, 0, 0, 255, 255, 255, 1, 0, 0, 0, 0, 0, 112, 255, 255, 175, 0, 0, 0, 0, 0, 0, 208, 255, 255, 63, 0, 0, 0, 0, 0, 0, 244, 255, 255, 13, 0, 0, 0, 0, 0, 0, 251, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 239, 0, 0, 0, 0, 0, 0, 128, 255, 255, 143, 0, 0, 0, 0, 0, 0, 240, 255, 255, 47, 0, 0, 0, 0, 0, 0, 246, 255, 255, 11, 0, 0, 0, 0, 0, 0, 253, 255, 255, 4, 0, 0, 0, 0, 0, 64, 255, 255, 223, 0, 0, 0, 0, 0, 0, 160, 255, 255, 111, 0, 0, 0, 0, 0, 0, 241, 255, 255, 15, 0, 0, 0, 0, 0, 0, 248, 255, 255, 8, 0, 0, 0, 0, 0, 0, 254, 255, 255, 2, 0, 0, 0, 0, 0, 96, 255, 255, 191, 0, 0, 0, 0, 0 }; -/* 8 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_56[] = { 22, 31, 25, 1, 30, 0, 0, 0, 96, 218, 254, 206, 73, 0, 0, 0, 0, 0, 112, 254, 255, 255, 255, 255, 77, 0, 0, 0, 0, 251, 255, 255, 255, 255, 255, 255, 8, 0, 0, 176, 255, 255, 255, 255, 255, 255, 255, 127, 0, 0, 245, 255, 255, 255, 239, 255, 255, 255, 255, 2, 0, 253, 255, 255, 60, 0, 80, 254, 255, 255, 9, 32, 255, 255, 223, 0, 0, 0, 242, 255, 255, 14, 80, 255, 255, 79, 0, 0, 0, 128, 255, 255, 47, 112, 255, 255, 15, 0, 0, 0, 64, 255, 255, 63, 96, 255, 255, 31, 0, 0, 0, 80, 255, 255, 47, 64, 255, 255, 95, 0, 0, 0, 144, 255, 255, 15, 0, 254, 255, 239, 1, 0, 0, 243, 255, 255, 11, 0, 245, 255, 255, 110, 2, 131, 255, 255, 255, 2, 0, 160, 255, 255, 255, 255, 255, 255, 255, 127, 0, 0, 0, 249, 255, 255, 255, 255, 255, 255, 6, 0, 0, 0, 227, 255, 255, 255, 255, 255, 207, 1, 0, 0, 96, 255, 255, 255, 255, 255, 255, 255, 78, 0, 0, 246, 255, 255, 239, 172, 252, 255, 255, 255, 3, 32, 255, 255, 239, 6, 0, 0, 248, 255, 255, 13, 144, 255, 255, 63, 0, 0, 0, 112, 255, 255, 95, 224, 255, 255, 10, 0, 0, 0, 0, 254, 255, 175, 240, 255, 255, 6, 0, 0, 0, 0, 250, 255, 207, 241, 255, 255, 7, 0, 0, 0, 0, 251, 255, 223, 240, 255, 255, 11, 0, 0, 0, 0, 254, 255, 207, 192, 255, 255, 111, 0, 0, 0, 144, 255, 255, 143, 112, 255, 255, 255, 41, 0, 48, 251, 255, 255, 63, 0, 253, 255, 255, 255, 223, 255, 255, 255, 255, 10, 0, 243, 255, 255, 255, 255, 255, 255, 255, 223, 1, 0, 64, 254, 255, 255, 255, 255, 255, 255, 28, 0, 0, 0, 161, 255, 255, 255, 255, 255, 142, 0, 0, 0, 0, 0, 97, 218, 254, 222, 90, 0, 0, 0 }; -/* 9 */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_57[] = { 22, 30, 24, 1, 30, 0, 0, 0, 80, 218, 254, 189, 39, 0, 0, 0, 0, 0, 112, 254, 255, 255, 255, 255, 26, 0, 0, 0, 16, 252, 255, 255, 255, 255, 255, 239, 4, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 250, 255, 255, 255, 255, 255, 255, 255, 239, 1, 48, 255, 255, 255, 93, 18, 148, 255, 255, 255, 8, 160, 255, 255, 159, 0, 0, 0, 244, 255, 255, 15, 240, 255, 255, 13, 0, 0, 0, 128, 255, 255, 95, 242, 255, 255, 6, 0, 0, 0, 16, 255, 255, 143, 244, 255, 255, 3, 0, 0, 0, 0, 254, 255, 159, 244, 255, 255, 3, 0, 0, 0, 0, 253, 255, 175, 242, 255, 255, 6, 0, 0, 0, 16, 255, 255, 143, 240, 255, 255, 12, 0, 0, 0, 112, 255, 255, 127, 176, 255, 255, 143, 0, 0, 0, 243, 255, 255, 63, 64, 255, 255, 255, 76, 17, 147, 255, 255, 255, 14, 0, 251, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 209, 255, 255, 255, 255, 255, 255, 255, 223, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 79, 0, 0, 0, 144, 255, 255, 255, 255, 255, 255, 10, 0, 0, 0, 0, 114, 236, 255, 255, 255, 239, 1, 0, 0, 0, 0, 0, 0, 242, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 11, 0, 0, 0, 0, 0, 0, 80, 255, 255, 255, 2, 0, 0, 0, 0, 0, 0, 224, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 13, 0, 0, 0, 0, 0, 0, 32, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 192, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 246, 255, 255, 30, 0, 0, 0, 0, 0, 0, 16, 254, 255, 255, 5, 0, 0, 0, 0, 0, 0, 144, 255, 255, 191, 0, 0, 0, 0, 0 }; -/* : */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_58[] = { 7, 21, 11, 2, 21, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 230, 238, 238, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 214, 221, 221, 5, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6, 247, 255, 255, 6 }; -/* ; */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_59[] = { 8, 25, 11, 1, 21, 64, 255, 255, 159, 64, 255, 255, 159, 64, 255, 255, 159, 64, 255, 255, 159, 64, 255, 255, 159, 64, 238, 238, 142, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 127, 112, 255, 255, 47, 128, 255, 255, 14, 160, 255, 255, 9, 192, 255, 255, 5, 224, 255, 255, 1, 240, 255, 207, 0, 241, 255, 127, 0, 243, 255, 63, 0, 163, 170, 10, 0 }; -/* < */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_60[] = { 19, 20, 23, 2, 22, 0, 0, 0, 0, 0, 0, 0, 0, 113, 10, 0, 0, 0, 0, 0, 0, 0, 180, 255, 12, 0, 0, 0, 0, 0, 16, 231, 255, 255, 12, 0, 0, 0, 0, 64, 251, 255, 255, 255, 12, 0, 0, 0, 129, 254, 255, 255, 255, 255, 12, 0, 0, 180, 255, 255, 255, 255, 255, 191, 5, 32, 232, 255, 255, 255, 255, 255, 125, 1, 0, 248, 255, 255, 255, 255, 255, 57, 0, 0, 0, 251, 255, 255, 255, 191, 5, 0, 0, 0, 0, 251, 255, 255, 126, 1, 0, 0, 0, 0, 0, 251, 255, 255, 191, 5, 0, 0, 0, 0, 0, 251, 255, 255, 255, 239, 57, 0, 0, 0, 0, 230, 255, 255, 255, 255, 255, 125, 1, 0, 0, 0, 164, 255, 255, 255, 255, 255, 191, 5, 0, 0, 0, 113, 253, 255, 255, 255, 255, 255, 8, 0, 0, 0, 64, 250, 255, 255, 255, 255, 12, 0, 0, 0, 0, 16, 215, 255, 255, 255, 12, 0, 0, 0, 0, 0, 0, 164, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 113, 253, 12, 0, 0, 0, 0, 0, 0, 0, 0, 48, 7 }; -/* = */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_61[] = { 19, 14, 23, 2, 19, 144, 153, 153, 153, 153, 153, 153, 153, 153, 1, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 240, 255, 255, 255, 255, 255, 255, 255, 255, 2, 144, 153, 153, 153, 153, 153, 153, 153, 153, 1 }; -/* > */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_62[] = { 19, 20, 23, 2, 22, 137, 2, 0, 0, 0, 0, 0, 0, 0, 0, 251, 191, 5, 0, 0, 0, 0, 0, 0, 0, 251, 255, 239, 40, 0, 0, 0, 0, 0, 0, 251, 255, 255, 255, 91, 0, 0, 0, 0, 0, 251, 255, 255, 255, 255, 142, 2, 0, 0, 0, 180, 255, 255, 255, 255, 255, 191, 5, 0, 0, 0, 113, 253, 255, 255, 255, 255, 239, 40, 0, 0, 0, 48, 233, 255, 255, 255, 255, 255, 9, 0, 0, 0, 0, 181, 255, 255, 255, 255, 12, 0, 0, 0, 0, 0, 97, 253, 255, 255, 12, 0, 0, 0, 0, 0, 164, 255, 255, 255, 12, 0, 0, 0, 32, 232, 255, 255, 255, 255, 12, 0, 0, 113, 253, 255, 255, 255, 255, 239, 7, 0, 181, 255, 255, 255, 255, 255, 191, 5, 0, 231, 255, 255, 255, 255, 255, 142, 1, 0, 0, 251, 255, 255, 255, 255, 75, 0, 0, 0, 0, 251, 255, 255, 239, 23, 0, 0, 0, 0, 0, 251, 255, 175, 4, 0, 0, 0, 0, 0, 0, 251, 125, 1, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* ? */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_63[] = { 20, 30, 22, 1, 30, 0, 0, 32, 200, 254, 223, 123, 2, 0, 0, 0, 32, 251, 255, 255, 255, 255, 175, 1, 0, 0, 244, 255, 255, 255, 255, 255, 255, 62, 0, 48, 255, 255, 255, 255, 255, 255, 255, 239, 2, 192, 255, 255, 255, 255, 255, 255, 255, 255, 11, 244, 255, 255, 175, 20, 98, 254, 255, 255, 63, 249, 255, 255, 8, 0, 0, 192, 255, 255, 143, 253, 255, 255, 0, 0, 0, 48, 255, 255, 175, 220, 221, 173, 0, 0, 0, 0, 255, 255, 207, 0, 0, 0, 0, 0, 0, 0, 255, 255, 175, 0, 0, 0, 0, 0, 0, 80, 255, 255, 143, 0, 0, 0, 0, 0, 0, 245, 255, 255, 63, 0, 0, 0, 0, 0, 178, 255, 255, 255, 12, 0, 0, 0, 0, 112, 255, 255, 255, 239, 2, 0, 0, 0, 0, 246, 255, 255, 255, 44, 0, 0, 0, 0, 32, 255, 255, 255, 94, 0, 0, 0, 0, 0, 128, 255, 255, 207, 1, 0, 0, 0, 0, 0, 208, 255, 255, 14, 0, 0, 0, 0, 0, 0, 224, 255, 255, 7, 0, 0, 0, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 0, 0, 0, 240, 255, 255, 3, 0, 0, 0, 0, 0, 0, 80, 85, 85, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 211, 221, 221, 6, 0, 0, 0, 0, 0, 0, 243, 255, 255, 6, 0, 0, 0, 0, 0, 0, 243, 255, 255, 6, 0, 0, 0, 0, 0, 0, 243, 255, 255, 6, 0, 0, 0, 0, 0, 0, 243, 255, 255, 6, 0, 0, 0, 0, 0, 0, 243, 255, 255, 6, 0, 0, 0 }; -/* @ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_64[] = { 37, 34, 40, 2, 29, 0, 0, 0, 0, 0, 0, 98, 202, 253, 223, 172, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 215, 255, 255, 255, 255, 255, 255, 158, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 255, 255, 255, 255, 255, 255, 255, 255, 159, 1, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 78, 0, 0, 0, 0, 0, 0, 48, 254, 255, 255, 255, 174, 121, 135, 218, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 243, 255, 255, 255, 56, 0, 0, 0, 0, 97, 253, 255, 255, 143, 0, 0, 0, 0, 32, 254, 255, 255, 26, 0, 0, 0, 0, 0, 0, 80, 254, 255, 255, 6, 0, 0, 0, 208, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 63, 0, 0, 0, 247, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 191, 0, 0, 16, 254, 255, 111, 0, 0, 48, 217, 255, 140, 2, 252, 239, 0, 225, 255, 255, 4, 0, 128, 255, 255, 11, 0, 16, 250, 255, 255, 255, 175, 255, 239, 0, 80, 255, 255, 12, 0, 208, 255, 255, 2, 0, 209, 255, 255, 255, 255, 255, 255, 239, 0, 0, 252, 255, 31, 0, 242, 255, 175, 0, 0, 252, 255, 255, 255, 255, 255, 255, 239, 0, 0, 245, 255, 111, 0, 247, 255, 95, 0, 80, 255, 255, 127, 2, 179, 255, 255, 239, 0, 0, 241, 255, 175, 0, 250, 255, 31, 0, 192, 255, 255, 3, 0, 0, 249, 255, 239, 0, 0, 208, 255, 207, 0, 251, 255, 14, 0, 241, 255, 159, 0, 0, 0, 224, 255, 239, 0, 0, 176, 255, 239, 0, 253, 255, 12, 0, 243, 255, 79, 0, 0, 0, 160, 255, 239, 0, 0, 160, 255, 255, 0, 254, 255, 11, 0, 244, 255, 47, 0, 0, 0, 128, 255, 239, 0, 0, 176, 255, 255, 0, 252, 255, 13, 0, 243, 255, 79, 0, 0, 0, 160, 255, 239, 0, 0, 192, 255, 239, 0, 251, 255, 14, 0, 241, 255, 159, 0, 0, 0, 224, 255, 239, 0, 0, 241, 255, 191, 0, 249, 255, 47, 0, 192, 255, 255, 3, 0, 0, 249, 255, 255, 1, 0, 249, 255, 127, 0, 245, 255, 127, 0, 80, 255, 255, 127, 2, 179, 255, 255, 255, 76, 164, 255, 255, 47, 0, 240, 255, 223, 0, 0, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 176, 255, 255, 7, 0, 209, 255, 255, 255, 255, 255, 254, 255, 255, 255, 255, 223, 0, 0, 48, 255, 255, 63, 0, 16, 251, 255, 255, 255, 191, 65, 255, 255, 255, 255, 27, 0, 0, 0, 250, 255, 239, 2, 0, 48, 217, 255, 172, 3, 0, 129, 252, 223, 73, 0, 0, 0, 0, 242, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 245, 255, 255, 255, 157, 37, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 193, 255, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115, 251, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 101, 102, 102, 102, 102, 2, 0, 0, 0, 0, 0 }; -/* A */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_65[] = { 29, 29, 29, 0, 29, 0, 0, 0, 0, 0, 250, 255, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 255, 255, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 245, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 175, 176, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 79, 80, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 15, 0, 255, 255, 239, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 10, 0, 250, 255, 255, 4, 0, 0, 0, 0, 0, 0, 250, 255, 255, 4, 0, 245, 255, 255, 10, 0, 0, 0, 0, 0, 0, 255, 255, 239, 0, 0, 240, 255, 255, 15, 0, 0, 0, 0, 0, 96, 255, 255, 159, 0, 0, 160, 255, 255, 95, 0, 0, 0, 0, 0, 192, 255, 255, 79, 0, 0, 64, 255, 255, 191, 0, 0, 0, 0, 0, 241, 255, 255, 14, 0, 0, 0, 254, 255, 255, 1, 0, 0, 0, 0, 247, 255, 255, 9, 0, 0, 0, 249, 255, 255, 7, 0, 0, 0, 0, 253, 255, 255, 4, 0, 0, 0, 244, 255, 255, 12, 0, 0, 0, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 47, 0, 0, 0, 128, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 143, 0, 0, 0, 224, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 0, 0, 0, 244, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 0, 0, 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 10, 0, 0, 255, 255, 255, 2, 0, 0, 0, 0, 0, 242, 255, 255, 15, 0, 80, 255, 255, 207, 0, 0, 0, 0, 0, 0, 192, 255, 255, 95, 0, 176, 255, 255, 111, 0, 0, 0, 0, 0, 0, 96, 255, 255, 191, 0, 241, 255, 255, 15, 0, 0, 0, 0, 0, 0, 16, 255, 255, 255, 1, 247, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 7, 253, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 12 }; -/* B */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_66[] = { 23, 29, 28, 3, 29, 253, 255, 255, 255, 255, 255, 255, 222, 73, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 27, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 2, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 253, 255, 255, 221, 221, 221, 237, 255, 255, 255, 111, 0, 253, 255, 159, 0, 0, 0, 0, 177, 255, 255, 207, 0, 253, 255, 159, 0, 0, 0, 0, 0, 253, 255, 255, 0, 253, 255, 159, 0, 0, 0, 0, 0, 247, 255, 255, 2, 253, 255, 159, 0, 0, 0, 0, 0, 244, 255, 255, 2, 253, 255, 159, 0, 0, 0, 0, 0, 247, 255, 255, 0, 253, 255, 159, 0, 0, 0, 0, 0, 253, 255, 207, 0, 253, 255, 159, 0, 0, 0, 0, 196, 255, 255, 111, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 6, 0, 253, 255, 255, 221, 221, 221, 221, 255, 255, 255, 63, 0, 253, 255, 159, 0, 0, 0, 0, 128, 255, 255, 207, 0, 253, 255, 159, 0, 0, 0, 0, 0, 248, 255, 255, 3, 253, 255, 159, 0, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 0, 224, 255, 255, 9, 253, 255, 159, 0, 0, 0, 0, 0, 240, 255, 255, 8, 253, 255, 159, 0, 0, 0, 0, 0, 248, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 112, 255, 255, 255, 3, 253, 255, 239, 221, 221, 221, 221, 255, 255, 255, 223, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 79, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 7, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 94, 0, 0, 253, 255, 255, 255, 255, 255, 255, 239, 107, 0, 0, 0 }; -/* C */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_67[] = { 29, 31, 31, 1, 30, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 45, 0, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 4, 0, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 253, 255, 255, 255, 123, 69, 166, 255, 255, 255, 239, 1, 0, 0, 160, 255, 255, 255, 26, 0, 0, 0, 177, 255, 255, 255, 9, 0, 0, 242, 255, 255, 127, 0, 0, 0, 0, 0, 247, 255, 255, 47, 0, 0, 250, 255, 255, 8, 0, 0, 0, 0, 0, 160, 255, 255, 159, 0, 16, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 0, 80, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 231, 238, 238, 3, 160, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 16, 17, 17, 0, 96, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 3, 16, 255, 255, 207, 0, 0, 0, 0, 0, 0, 16, 255, 255, 239, 0, 0, 250, 255, 255, 7, 0, 0, 0, 0, 0, 160, 255, 255, 159, 0, 0, 242, 255, 255, 111, 0, 0, 0, 0, 0, 247, 255, 255, 47, 0, 0, 160, 255, 255, 255, 26, 0, 0, 0, 177, 255, 255, 255, 9, 0, 0, 0, 253, 255, 255, 255, 107, 69, 150, 255, 255, 255, 223, 1, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 4, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 61, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0 }; -/* D */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_68[] = { 26, 29, 30, 3, 29, 253, 255, 255, 255, 255, 239, 189, 39, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 93, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 44, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 4, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 79, 0, 0, 253, 255, 191, 68, 68, 84, 166, 255, 255, 255, 239, 2, 0, 253, 255, 159, 0, 0, 0, 0, 129, 255, 255, 255, 12, 0, 253, 255, 159, 0, 0, 0, 0, 0, 244, 255, 255, 95, 0, 253, 255, 159, 0, 0, 0, 0, 0, 64, 255, 255, 223, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 249, 255, 255, 3, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 8, 253, 255, 159, 0, 0, 0, 0, 0, 0, 192, 255, 255, 13, 253, 255, 159, 0, 0, 0, 0, 0, 0, 128, 255, 255, 15, 253, 255, 159, 0, 0, 0, 0, 0, 0, 96, 255, 255, 15, 253, 255, 159, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 253, 255, 159, 0, 0, 0, 0, 0, 0, 96, 255, 255, 15, 253, 255, 159, 0, 0, 0, 0, 0, 0, 128, 255, 255, 15, 253, 255, 159, 0, 0, 0, 0, 0, 0, 192, 255, 255, 13, 253, 255, 159, 0, 0, 0, 0, 0, 0, 241, 255, 255, 8, 253, 255, 159, 0, 0, 0, 0, 0, 0, 249, 255, 255, 3, 253, 255, 159, 0, 0, 0, 0, 0, 64, 255, 255, 223, 0, 253, 255, 159, 0, 0, 0, 0, 0, 244, 255, 255, 95, 0, 253, 255, 159, 0, 0, 0, 0, 128, 255, 255, 255, 13, 0, 253, 255, 191, 51, 51, 68, 166, 255, 255, 255, 239, 2, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 79, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 4, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 44, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 93, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 189, 55, 0, 0, 0, 0, 0 }; -/* E */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_69[] = { 20, 29, 25, 3, 29, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 175, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 15, 253, 255, 255, 255, 255, 255, 255, 255, 255, 15, 253, 255, 255, 255, 255, 255, 255, 255, 255, 15, 253, 255, 255, 255, 255, 255, 255, 255, 255, 15, 253, 255, 255, 255, 255, 255, 255, 255, 255, 15, 253, 255, 175, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239 }; -/* F */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_70[] = { 20, 29, 25, 3, 29, 253, 255, 255, 255, 255, 255, 255, 255, 255, 175, 253, 255, 255, 255, 255, 255, 255, 255, 255, 175, 253, 255, 255, 255, 255, 255, 255, 255, 255, 175, 253, 255, 255, 255, 255, 255, 255, 255, 255, 175, 253, 255, 255, 255, 255, 255, 255, 255, 255, 175, 253, 255, 175, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 253, 255, 175, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0 }; -/* G */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_71[] = { 29, 31, 32, 1, 30, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 110, 0, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 45, 0, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 4, 0, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 0, 0, 0, 0, 253, 255, 255, 255, 123, 85, 167, 255, 255, 255, 239, 1, 0, 0, 144, 255, 255, 255, 26, 0, 0, 0, 162, 255, 255, 255, 10, 0, 0, 242, 255, 255, 127, 0, 0, 0, 0, 0, 248, 255, 255, 63, 0, 0, 250, 255, 255, 8, 0, 0, 0, 0, 0, 160, 255, 255, 175, 0, 16, 255, 255, 223, 0, 0, 0, 0, 0, 0, 16, 254, 255, 255, 0, 80, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 198, 204, 204, 3, 144, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 6, 0, 0, 0, 0, 34, 34, 34, 34, 34, 34, 1, 241, 255, 255, 5, 0, 0, 0, 48, 255, 255, 255, 255, 255, 255, 9, 240, 255, 255, 6, 0, 0, 0, 48, 255, 255, 255, 255, 255, 255, 9, 240, 255, 255, 7, 0, 0, 0, 48, 255, 255, 255, 255, 255, 255, 9, 224, 255, 255, 10, 0, 0, 0, 48, 255, 255, 255, 255, 255, 255, 9, 160, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 9, 96, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 9, 16, 255, 255, 207, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 9, 0, 251, 255, 255, 7, 0, 0, 0, 0, 0, 48, 255, 255, 255, 9, 0, 243, 255, 255, 111, 0, 0, 0, 0, 0, 227, 255, 255, 255, 9, 0, 160, 255, 255, 255, 25, 0, 0, 0, 112, 255, 255, 255, 255, 9, 0, 0, 253, 255, 255, 255, 107, 68, 150, 254, 255, 255, 255, 255, 9, 0, 0, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 0, 32, 254, 255, 255, 255, 255, 255, 255, 255, 159, 255, 255, 9, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 7, 253, 255, 9, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 60, 0, 250, 255, 9, 0, 0, 0, 0, 0, 114, 219, 254, 206, 56, 0, 0, 0, 0, 0 }; -/* H */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_72[] = { 25, 29, 30, 3, 29, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 207, 119, 119, 119, 119, 119, 119, 248, 255, 255, 4, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 0, 242, 255, 255, 4 }; -/* I */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_73[] = { 6, 29, 12, 3, 29, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159, 253, 255, 159 }; -/* J */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_74[] = { 15, 29, 17, 0, 29, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 242, 255, 255, 4, 0, 0, 0, 0, 243, 255, 255, 4, 0, 0, 0, 0, 245, 255, 255, 4, 50, 51, 51, 84, 253, 255, 255, 3, 249, 255, 255, 255, 255, 255, 255, 1, 249, 255, 255, 255, 255, 255, 239, 0, 249, 255, 255, 255, 255, 255, 127, 0, 249, 255, 255, 255, 255, 255, 11, 0, 249, 255, 255, 255, 223, 91, 0, 0 }; -/* K */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_75[] = { 24, 29, 25, 3, 29, 253, 255, 159, 0, 0, 0, 0, 176, 255, 255, 239, 1, 253, 255, 159, 0, 0, 0, 0, 247, 255, 255, 79, 0, 253, 255, 159, 0, 0, 0, 64, 255, 255, 255, 7, 0, 253, 255, 159, 0, 0, 0, 225, 255, 255, 175, 0, 0, 253, 255, 159, 0, 0, 0, 252, 255, 255, 13, 0, 0, 253, 255, 159, 0, 0, 128, 255, 255, 255, 2, 0, 0, 253, 255, 159, 0, 0, 245, 255, 255, 95, 0, 0, 0, 253, 255, 159, 0, 32, 255, 255, 255, 9, 0, 0, 0, 253, 255, 159, 0, 208, 255, 255, 207, 0, 0, 0, 0, 253, 255, 159, 0, 250, 255, 255, 30, 0, 0, 0, 0, 253, 255, 159, 96, 255, 255, 255, 3, 0, 0, 0, 0, 253, 255, 159, 243, 255, 255, 127, 0, 0, 0, 0, 0, 253, 255, 175, 254, 255, 255, 10, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 253, 255, 239, 255, 255, 255, 4, 0, 0, 0, 0, 0, 253, 255, 159, 249, 255, 255, 46, 0, 0, 0, 0, 0, 253, 255, 159, 192, 255, 255, 223, 0, 0, 0, 0, 0, 253, 255, 159, 16, 254, 255, 255, 11, 0, 0, 0, 0, 253, 255, 159, 0, 243, 255, 255, 143, 0, 0, 0, 0, 253, 255, 159, 0, 80, 255, 255, 255, 5, 0, 0, 0, 253, 255, 159, 0, 0, 248, 255, 255, 47, 0, 0, 0, 253, 255, 159, 0, 0, 176, 255, 255, 239, 1, 0, 0, 253, 255, 159, 0, 0, 16, 253, 255, 255, 12, 0, 0, 253, 255, 159, 0, 0, 0, 242, 255, 255, 159, 0, 0, 253, 255, 159, 0, 0, 0, 80, 255, 255, 255, 6, 0, 253, 255, 159, 0, 0, 0, 0, 247, 255, 255, 63, 0, 253, 255, 159, 0, 0, 0, 0, 160, 255, 255, 239, 1, 253, 255, 159, 0, 0, 0, 0, 0, 253, 255, 255, 12 }; -/* L */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_76[] = { 20, 29, 23, 3, 29, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 253, 255, 191, 51, 51, 51, 51, 51, 51, 19, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127, 253, 255, 255, 255, 255, 255, 255, 255, 255, 127 }; -/* M */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_77[] = { 33, 29, 39, 3, 29, 253, 255, 255, 255, 47, 0, 0, 0, 0, 0, 0, 128, 255, 255, 255, 255, 7, 253, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 7, 253, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 242, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 2, 0, 0, 0, 0, 0, 248, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 8, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 13, 0, 0, 0, 0, 48, 255, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 63, 0, 0, 0, 0, 128, 255, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 143, 0, 0, 0, 0, 224, 255, 255, 255, 255, 255, 7, 253, 255, 255, 255, 255, 239, 0, 0, 0, 0, 243, 255, 255, 255, 255, 255, 7, 253, 255, 175, 246, 255, 255, 3, 0, 0, 0, 249, 255, 255, 241, 255, 255, 7, 253, 255, 159, 241, 255, 255, 9, 0, 0, 0, 254, 255, 175, 240, 255, 255, 7, 253, 255, 159, 176, 255, 255, 14, 0, 0, 64, 255, 255, 95, 240, 255, 255, 7, 253, 255, 159, 80, 255, 255, 79, 0, 0, 144, 255, 255, 15, 240, 255, 255, 7, 253, 255, 159, 0, 255, 255, 159, 0, 0, 240, 255, 255, 10, 240, 255, 255, 7, 253, 255, 159, 0, 250, 255, 239, 0, 0, 244, 255, 255, 4, 240, 255, 255, 7, 253, 255, 159, 0, 245, 255, 255, 4, 0, 250, 255, 239, 0, 240, 255, 255, 7, 253, 255, 159, 0, 240, 255, 255, 9, 0, 255, 255, 159, 0, 240, 255, 255, 7, 253, 255, 159, 0, 160, 255, 255, 15, 80, 255, 255, 63, 0, 240, 255, 255, 7, 253, 255, 159, 0, 64, 255, 255, 79, 160, 255, 255, 14, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 254, 255, 175, 240, 255, 255, 8, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 249, 255, 255, 253, 255, 255, 3, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 243, 255, 255, 255, 255, 223, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 224, 255, 255, 255, 255, 143, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 128, 255, 255, 255, 255, 47, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 48, 255, 255, 255, 255, 13, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 253, 255, 255, 255, 7, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 247, 255, 255, 255, 1, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 242, 255, 255, 207, 0, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 192, 255, 255, 111, 0, 0, 0, 240, 255, 255, 7 }; -/* N */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_78[] = { 25, 29, 31, 3, 29, 253, 255, 255, 207, 0, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 4, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 13, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 95, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 239, 0, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 255, 7, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 255, 14, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 255, 143, 0, 0, 0, 240, 255, 255, 7, 253, 255, 255, 255, 255, 255, 1, 0, 0, 240, 255, 255, 7, 253, 255, 175, 245, 255, 255, 9, 0, 0, 240, 255, 255, 7, 253, 255, 159, 192, 255, 255, 47, 0, 0, 240, 255, 255, 7, 253, 255, 159, 48, 255, 255, 175, 0, 0, 240, 255, 255, 7, 253, 255, 159, 0, 251, 255, 255, 3, 0, 240, 255, 255, 7, 253, 255, 159, 0, 242, 255, 255, 11, 0, 240, 255, 255, 7, 253, 255, 159, 0, 160, 255, 255, 79, 0, 240, 255, 255, 7, 253, 255, 159, 0, 16, 255, 255, 207, 0, 240, 255, 255, 7, 253, 255, 159, 0, 0, 248, 255, 255, 5, 240, 255, 255, 7, 253, 255, 159, 0, 0, 241, 255, 255, 13, 240, 255, 255, 7, 253, 255, 159, 0, 0, 112, 255, 255, 111, 240, 255, 255, 7, 253, 255, 159, 0, 0, 0, 254, 255, 239, 241, 255, 255, 7, 253, 255, 159, 0, 0, 0, 246, 255, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 208, 255, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 80, 255, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 252, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 244, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 176, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 48, 255, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 0, 250, 255, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 0, 242, 255, 255, 255, 7 }; -/* O */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_79[] = { 30, 31, 32, 1, 30, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 77, 0, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 111, 0, 0, 0, 0, 253, 255, 255, 255, 123, 69, 150, 254, 255, 255, 255, 3, 0, 0, 160, 255, 255, 255, 26, 0, 0, 0, 112, 255, 255, 255, 14, 0, 0, 242, 255, 255, 127, 0, 0, 0, 0, 0, 227, 255, 255, 127, 0, 0, 250, 255, 255, 8, 0, 0, 0, 0, 0, 48, 255, 255, 239, 0, 16, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 6, 80, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 11, 160, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 15, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 47, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 95, 241, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 111, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 95, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 79, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 47, 160, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 15, 96, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 11, 16, 255, 255, 207, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 6, 0, 250, 255, 255, 7, 0, 0, 0, 0, 0, 48, 255, 255, 239, 0, 0, 242, 255, 255, 111, 0, 0, 0, 0, 0, 226, 255, 255, 127, 0, 0, 160, 255, 255, 255, 26, 0, 0, 0, 96, 255, 255, 255, 14, 0, 0, 0, 253, 255, 255, 255, 107, 69, 150, 254, 255, 255, 255, 3, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 111, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 6, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 77, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0 }; -/* P */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_80[] = { 23, 29, 27, 3, 29, 253, 255, 255, 255, 255, 255, 255, 206, 39, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 207, 1, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 95, 0, 253, 255, 191, 68, 68, 68, 84, 248, 255, 255, 223, 0, 253, 255, 159, 0, 0, 0, 0, 16, 254, 255, 255, 2, 253, 255, 159, 0, 0, 0, 0, 0, 245, 255, 255, 6, 253, 255, 159, 0, 0, 0, 0, 0, 240, 255, 255, 8, 253, 255, 159, 0, 0, 0, 0, 0, 224, 255, 255, 9, 253, 255, 159, 0, 0, 0, 0, 0, 240, 255, 255, 8, 253, 255, 159, 0, 0, 0, 0, 0, 243, 255, 255, 7, 253, 255, 159, 0, 0, 0, 0, 0, 252, 255, 255, 3, 253, 255, 159, 0, 0, 0, 0, 196, 255, 255, 239, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 45, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 108, 0, 0, 0, 253, 255, 191, 68, 68, 68, 52, 2, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -/* Q */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_81[] = { 30, 33, 32, 1, 30, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 126, 0, 0, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 77, 0, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 5, 0, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 111, 0, 0, 0, 0, 253, 255, 255, 255, 123, 69, 150, 254, 255, 255, 255, 3, 0, 0, 160, 255, 255, 255, 26, 0, 0, 0, 112, 255, 255, 255, 14, 0, 0, 242, 255, 255, 127, 0, 0, 0, 0, 0, 227, 255, 255, 127, 0, 0, 250, 255, 255, 8, 0, 0, 0, 0, 0, 48, 255, 255, 239, 0, 16, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 6, 80, 255, 255, 95, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 11, 160, 255, 255, 15, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 15, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 47, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 95, 241, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 111, 240, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 16, 255, 255, 95, 240, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 79, 208, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 47, 160, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 15, 96, 255, 255, 95, 0, 0, 161, 170, 170, 42, 0, 240, 255, 255, 11, 16, 255, 255, 207, 0, 0, 80, 255, 255, 239, 1, 247, 255, 255, 6, 0, 250, 255, 255, 7, 0, 0, 247, 255, 255, 60, 255, 255, 255, 1, 0, 242, 255, 255, 111, 0, 0, 144, 255, 255, 255, 255, 255, 143, 0, 0, 160, 255, 255, 255, 26, 0, 0, 251, 255, 255, 255, 255, 14, 0, 0, 0, 253, 255, 255, 255, 107, 69, 247, 255, 255, 255, 255, 4, 0, 0, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 255, 111, 0, 0, 0, 0, 32, 253, 255, 255, 255, 255, 255, 255, 255, 255, 79, 0, 0, 0, 0, 0, 177, 255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 0, 0, 0, 0, 0, 196, 255, 255, 255, 255, 255, 255, 255, 255, 30, 0, 0, 0, 0, 0, 0, 114, 219, 254, 205, 73, 96, 255, 255, 223, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 170, 170, 106 }; -/* R */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_82[] = { 24, 29, 28, 3, 29, 253, 255, 255, 255, 255, 255, 255, 206, 40, 0, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 207, 1, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 12, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 0, 253, 255, 191, 68, 68, 68, 68, 232, 255, 255, 239, 0, 253, 255, 159, 0, 0, 0, 0, 16, 253, 255, 255, 5, 253, 255, 159, 0, 0, 0, 0, 0, 243, 255, 255, 9, 253, 255, 159, 0, 0, 0, 0, 0, 208, 255, 255, 11, 253, 255, 159, 0, 0, 0, 0, 0, 176, 255, 255, 12, 253, 255, 159, 0, 0, 0, 0, 0, 192, 255, 255, 12, 253, 255, 159, 0, 0, 0, 0, 0, 241, 255, 255, 10, 253, 255, 159, 0, 0, 0, 0, 0, 250, 255, 255, 6, 253, 255, 159, 0, 0, 0, 0, 179, 255, 255, 255, 1, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 159, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 239, 3, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 27, 0, 0, 253, 255, 255, 255, 255, 255, 255, 223, 73, 0, 0, 0, 253, 255, 175, 80, 255, 255, 255, 10, 0, 0, 0, 0, 253, 255, 159, 0, 245, 255, 255, 159, 0, 0, 0, 0, 253, 255, 159, 0, 96, 255, 255, 255, 8, 0, 0, 0, 253, 255, 159, 0, 0, 247, 255, 255, 127, 0, 0, 0, 253, 255, 159, 0, 0, 112, 255, 255, 255, 7, 0, 0, 253, 255, 159, 0, 0, 0, 248, 255, 255, 111, 0, 0, 253, 255, 159, 0, 0, 0, 144, 255, 255, 255, 5, 0, 253, 255, 159, 0, 0, 0, 0, 250, 255, 255, 95, 0, 253, 255, 159, 0, 0, 0, 0, 160, 255, 255, 255, 4, 253, 255, 159, 0, 0, 0, 0, 0, 251, 255, 255, 63 }; -/* S */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_83[] = { 24, 31, 27, 1, 30, 0, 0, 0, 64, 201, 254, 239, 156, 21, 0, 0, 0, 0, 0, 96, 254, 255, 255, 255, 255, 255, 24, 0, 0, 0, 16, 252, 255, 255, 255, 255, 255, 255, 239, 3, 0, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 47, 0, 0, 249, 255, 255, 255, 255, 255, 255, 255, 255, 223, 0, 32, 255, 255, 255, 109, 19, 65, 231, 255, 255, 255, 6, 128, 255, 255, 175, 0, 0, 0, 0, 250, 255, 255, 12, 192, 255, 255, 14, 0, 0, 0, 0, 208, 255, 255, 31, 208, 255, 255, 10, 0, 0, 0, 0, 96, 255, 255, 63, 208, 255, 255, 9, 0, 0, 0, 0, 32, 221, 221, 77, 160, 255, 255, 14, 0, 0, 0, 0, 0, 0, 0, 0, 128, 255, 255, 207, 2, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 255, 223, 89, 2, 0, 0, 0, 0, 0, 0, 250, 255, 255, 255, 255, 255, 156, 21, 0, 0, 0, 0, 209, 255, 255, 255, 255, 255, 255, 255, 75, 0, 0, 0, 0, 250, 255, 255, 255, 255, 255, 255, 255, 27, 0, 0, 0, 64, 234, 255, 255, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 99, 201, 255, 255, 255, 255, 255, 10, 0, 0, 0, 0, 0, 0, 32, 166, 255, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 0, 211, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 175, 214, 221, 221, 0, 0, 0, 0, 0, 0, 252, 255, 191, 246, 255, 255, 3, 0, 0, 0, 0, 0, 252, 255, 191, 243, 255, 255, 12, 0, 0, 0, 0, 16, 255, 255, 175, 224, 255, 255, 175, 1, 0, 0, 0, 192, 255, 255, 111, 112, 255, 255, 255, 143, 36, 32, 132, 254, 255, 255, 31, 0, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 9, 0, 226, 255, 255, 255, 255, 255, 255, 255, 255, 207, 0, 0, 32, 252, 255, 255, 255, 255, 255, 255, 255, 28, 0, 0, 0, 112, 253, 255, 255, 255, 255, 255, 110, 0, 0, 0, 0, 0, 64, 200, 237, 239, 189, 72, 0, 0, 0 }; -/* T */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_84[] = { 24, 29, 25, 0, 29, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 242, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 64, 68, 68, 68, 132, 255, 255, 95, 68, 68, 68, 52, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 31, 0, 0, 0, 0 }; -/* U */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_85[] = { 26, 30, 30, 2, 29, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 6, 0, 0, 0, 0, 0, 32, 255, 255, 79, 240, 255, 255, 7, 0, 0, 0, 0, 0, 48, 255, 255, 63, 224, 255, 255, 10, 0, 0, 0, 0, 0, 96, 255, 255, 47, 192, 255, 255, 14, 0, 0, 0, 0, 0, 176, 255, 255, 15, 128, 255, 255, 143, 0, 0, 0, 0, 0, 245, 255, 255, 11, 48, 255, 255, 255, 3, 0, 0, 0, 16, 254, 255, 255, 7, 0, 252, 255, 255, 127, 0, 0, 0, 228, 255, 255, 255, 1, 0, 245, 255, 255, 255, 124, 68, 182, 255, 255, 255, 143, 0, 0, 160, 255, 255, 255, 255, 255, 255, 255, 255, 255, 13, 0, 0, 0, 252, 255, 255, 255, 255, 255, 255, 255, 239, 2, 0, 0, 0, 160, 255, 255, 255, 255, 255, 255, 255, 28, 0, 0, 0, 0, 0, 213, 255, 255, 255, 255, 255, 110, 0, 0, 0, 0, 0, 0, 0, 131, 220, 255, 206, 73, 0, 0, 0, 0 }; -/* V */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_86[] = { 29, 29, 29, 0, 29, 250, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 2, 244, 255, 255, 12, 0, 0, 0, 0, 0, 0, 64, 255, 255, 223, 0, 224, 255, 255, 47, 0, 0, 0, 0, 0, 0, 144, 255, 255, 127, 0, 144, 255, 255, 127, 0, 0, 0, 0, 0, 0, 224, 255, 255, 47, 0, 48, 255, 255, 223, 0, 0, 0, 0, 0, 0, 244, 255, 255, 12, 0, 0, 254, 255, 255, 2, 0, 0, 0, 0, 0, 249, 255, 255, 6, 0, 0, 248, 255, 255, 8, 0, 0, 0, 0, 0, 254, 255, 255, 1, 0, 0, 243, 255, 255, 13, 0, 0, 0, 0, 64, 255, 255, 191, 0, 0, 0, 208, 255, 255, 47, 0, 0, 0, 0, 160, 255, 255, 111, 0, 0, 0, 112, 255, 255, 143, 0, 0, 0, 0, 240, 255, 255, 31, 0, 0, 0, 32, 255, 255, 223, 0, 0, 0, 0, 245, 255, 255, 11, 0, 0, 0, 0, 252, 255, 255, 3, 0, 0, 0, 250, 255, 255, 5, 0, 0, 0, 0, 247, 255, 255, 8, 0, 0, 0, 255, 255, 255, 0, 0, 0, 0, 0, 241, 255, 255, 13, 0, 0, 80, 255, 255, 175, 0, 0, 0, 0, 0, 192, 255, 255, 63, 0, 0, 160, 255, 255, 79, 0, 0, 0, 0, 0, 96, 255, 255, 143, 0, 0, 240, 255, 255, 14, 0, 0, 0, 0, 0, 16, 255, 255, 239, 0, 0, 245, 255, 255, 9, 0, 0, 0, 0, 0, 0, 251, 255, 255, 3, 0, 251, 255, 255, 4, 0, 0, 0, 0, 0, 0, 245, 255, 255, 9, 0, 255, 255, 239, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 14, 80, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 79, 176, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 159, 241, 255, 255, 13, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 252, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 255, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 6, 0, 0, 0, 0, 0 }; -/* W */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_87[] = { 41, 29, 41, 0, 29, 250, 255, 255, 6, 0, 0, 0, 0, 176, 255, 255, 223, 0, 0, 0, 0, 0, 244, 255, 255, 13, 246, 255, 255, 10, 0, 0, 0, 0, 240, 255, 255, 255, 1, 0, 0, 0, 0, 248, 255, 255, 9, 242, 255, 255, 14, 0, 0, 0, 0, 243, 255, 255, 255, 5, 0, 0, 0, 0, 252, 255, 255, 5, 224, 255, 255, 47, 0, 0, 0, 0, 247, 255, 255, 255, 10, 0, 0, 0, 0, 255, 255, 255, 1, 160, 255, 255, 111, 0, 0, 0, 0, 251, 255, 255, 255, 14, 0, 0, 0, 64, 255, 255, 207, 0, 96, 255, 255, 175, 0, 0, 0, 0, 255, 255, 255, 255, 47, 0, 0, 0, 128, 255, 255, 143, 0, 32, 255, 255, 239, 0, 0, 0, 64, 255, 255, 255, 255, 111, 0, 0, 0, 192, 255, 255, 79, 0, 0, 254, 255, 255, 2, 0, 0, 128, 255, 255, 255, 255, 175, 0, 0, 0, 240, 255, 255, 15, 0, 0, 250, 255, 255, 6, 0, 0, 192, 255, 255, 255, 255, 239, 0, 0, 0, 244, 255, 255, 12, 0, 0, 246, 255, 255, 10, 0, 0, 240, 255, 255, 228, 255, 255, 3, 0, 0, 248, 255, 255, 8, 0, 0, 242, 255, 255, 14, 0, 0, 244, 255, 223, 160, 255, 255, 7, 0, 0, 252, 255, 255, 4, 0, 0, 224, 255, 255, 47, 0, 0, 249, 255, 159, 96, 255, 255, 11, 0, 0, 255, 255, 255, 0, 0, 0, 160, 255, 255, 111, 0, 0, 253, 255, 95, 32, 255, 255, 15, 0, 64, 255, 255, 207, 0, 0, 0, 96, 255, 255, 175, 0, 16, 255, 255, 31, 0, 254, 255, 63, 0, 128, 255, 255, 143, 0, 0, 0, 32, 255, 255, 239, 0, 80, 255, 255, 12, 0, 250, 255, 127, 0, 192, 255, 255, 79, 0, 0, 0, 0, 253, 255, 255, 2, 144, 255, 255, 8, 0, 246, 255, 207, 0, 240, 255, 255, 15, 0, 0, 0, 0, 249, 255, 255, 6, 208, 255, 255, 4, 0, 242, 255, 255, 0, 244, 255, 255, 12, 0, 0, 0, 0, 245, 255, 255, 10, 242, 255, 255, 0, 0, 224, 255, 255, 4, 248, 255, 255, 8, 0, 0, 0, 0, 241, 255, 255, 14, 246, 255, 207, 0, 0, 160, 255, 255, 8, 252, 255, 255, 4, 0, 0, 0, 0, 208, 255, 255, 47, 250, 255, 143, 0, 0, 96, 255, 255, 12, 255, 255, 255, 0, 0, 0, 0, 0, 144, 255, 255, 223, 255, 255, 79, 0, 0, 32, 255, 255, 223, 255, 255, 191, 0, 0, 0, 0, 0, 80, 255, 255, 255, 255, 255, 15, 0, 0, 0, 254, 255, 255, 255, 255, 127, 0, 0, 0, 0, 0, 16, 255, 255, 255, 255, 255, 12, 0, 0, 0, 250, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 8, 0, 0, 0, 245, 255, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 249, 255, 255, 255, 255, 4, 0, 0, 0, 241, 255, 255, 255, 255, 11, 0, 0, 0, 0, 0, 0, 245, 255, 255, 255, 255, 0, 0, 0, 0, 208, 255, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 241, 255, 255, 255, 191, 0, 0, 0, 0, 144, 255, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 127, 0, 0, 0, 0, 80, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 144, 255, 255, 255, 63, 0, 0, 0, 0, 16, 255, 255, 255, 191, 0, 0, 0, 0 }; -/* X */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_88[] = { 29, 29, 28, 0, 29, 112, 255, 255, 255, 1, 0, 0, 0, 0, 0, 243, 255, 255, 95, 0, 0, 252, 255, 255, 11, 0, 0, 0, 0, 0, 253, 255, 255, 10, 0, 0, 242, 255, 255, 95, 0, 0, 0, 0, 112, 255, 255, 239, 1, 0, 0, 112, 255, 255, 239, 1, 0, 0, 0, 242, 255, 255, 95, 0, 0, 0, 0, 252, 255, 255, 11, 0, 0, 0, 252, 255, 255, 10, 0, 0, 0, 0, 242, 255, 255, 95, 0, 0, 112, 255, 255, 239, 1, 0, 0, 0, 0, 112, 255, 255, 239, 1, 0, 242, 255, 255, 79, 0, 0, 0, 0, 0, 0, 252, 255, 255, 10, 0, 252, 255, 255, 10, 0, 0, 0, 0, 0, 0, 242, 255, 255, 95, 112, 255, 255, 239, 1, 0, 0, 0, 0, 0, 0, 96, 255, 255, 239, 247, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 0, 252, 255, 255, 255, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 255, 255, 239, 1, 0, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 251, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 255, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 255, 255, 255, 8, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 255, 250, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 225, 255, 255, 127, 144, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 250, 255, 255, 12, 0, 253, 255, 255, 8, 0, 0, 0, 0, 0, 80, 255, 255, 255, 2, 0, 243, 255, 255, 63, 0, 0, 0, 0, 0, 225, 255, 255, 111, 0, 0, 144, 255, 255, 223, 0, 0, 0, 0, 0, 251, 255, 255, 12, 0, 0, 0, 253, 255, 255, 9, 0, 0, 0, 96, 255, 255, 255, 2, 0, 0, 0, 243, 255, 255, 79, 0, 0, 0, 241, 255, 255, 111, 0, 0, 0, 0, 128, 255, 255, 239, 0, 0, 0, 251, 255, 255, 11, 0, 0, 0, 0, 0, 253, 255, 255, 9, 0, 96, 255, 255, 255, 2, 0, 0, 0, 0, 0, 243, 255, 255, 79, 0, 242, 255, 255, 111, 0, 0, 0, 0, 0, 0, 128, 255, 255, 239, 1 }; -/* Y */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_89[] = { 28, 29, 27, 0, 29, 242, 255, 255, 14, 0, 0, 0, 0, 0, 0, 224, 255, 255, 47, 144, 255, 255, 127, 0, 0, 0, 0, 0, 0, 247, 255, 255, 9, 16, 255, 255, 255, 1, 0, 0, 0, 0, 16, 255, 255, 255, 1, 0, 247, 255, 255, 9, 0, 0, 0, 0, 144, 255, 255, 127, 0, 0, 208, 255, 255, 47, 0, 0, 0, 0, 242, 255, 255, 14, 0, 0, 80, 255, 255, 191, 0, 0, 0, 0, 251, 255, 255, 5, 0, 0, 0, 252, 255, 255, 4, 0, 0, 64, 255, 255, 207, 0, 0, 0, 0, 243, 255, 255, 13, 0, 0, 192, 255, 255, 63, 0, 0, 0, 0, 160, 255, 255, 111, 0, 0, 245, 255, 255, 10, 0, 0, 0, 0, 16, 255, 255, 239, 0, 0, 254, 255, 255, 2, 0, 0, 0, 0, 0, 248, 255, 255, 8, 112, 255, 255, 143, 0, 0, 0, 0, 0, 0, 224, 255, 255, 31, 241, 255, 255, 30, 0, 0, 0, 0, 0, 0, 96, 255, 255, 207, 252, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 255, 255, 79, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 32, 255, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 255, 255, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 11, 0, 0, 0, 0, 0 }; -/* Z */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_90[] = { 23, 29, 25, 1, 29, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 245, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 11, 65, 68, 68, 68, 68, 68, 68, 228, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 111, 0, 0, 0, 0, 0, 0, 0, 96, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 207, 0, 0, 0, 0, 0, 0, 0, 16, 254, 255, 255, 30, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 4, 0, 0, 0, 0, 0, 0, 0, 248, 255, 255, 127, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 255, 10, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 11, 0, 0, 0, 0, 0, 0, 0, 226, 255, 255, 239, 1, 0, 0, 0, 0, 0, 0, 0, 252, 255, 255, 63, 0, 0, 0, 0, 0, 0, 0, 160, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 0, 246, 255, 255, 159, 0, 0, 0, 0, 0, 0, 0, 48, 255, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 225, 255, 255, 255, 53, 51, 51, 51, 51, 51, 51, 3, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14, 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 14 }; -/* [ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_91[] = { 11, 39, 15, 3, 31, 216, 221, 221, 221, 221, 11, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 159, 0, 0, 0, 250, 255, 239, 221, 221, 11, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13, 250, 255, 255, 255, 255, 13 }; -/* \ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_92[] = { 17, 40, 17, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 253, 255, 111, 0, 0, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 0, 0, 243, 255, 255, 0, 0, 0, 0, 0, 0, 224, 255, 255, 4, 0, 0, 0, 0, 0, 160, 255, 255, 9, 0, 0, 0, 0, 0, 80, 255, 255, 14, 0, 0, 0, 0, 0, 16, 255, 255, 47, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 0, 0, 247, 255, 207, 0, 0, 0, 0, 0, 0, 242, 255, 255, 1, 0, 0, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 0, 0, 144, 255, 255, 10, 0, 0, 0, 0, 0, 64, 255, 255, 15, 0, 0, 0, 0, 0, 0, 255, 255, 79, 0, 0, 0, 0, 0, 0, 251, 255, 143, 0, 0, 0, 0, 0, 0, 246, 255, 223, 0, 0, 0, 0, 0, 0, 241, 255, 255, 2, 0, 0, 0, 0, 0, 192, 255, 255, 7, 0, 0, 0, 0, 0, 128, 255, 255, 11, 0, 0, 0, 0, 0, 48, 255, 255, 15, 0, 0, 0, 0, 0, 0, 254, 255, 95, 0, 0, 0, 0, 0, 0, 250, 255, 159, 0, 0, 0, 0, 0, 0, 245, 255, 239, 0, 0, 0, 0, 0, 0, 240, 255, 255, 3, 0, 0, 0, 0, 0, 176, 255, 255, 8, 0, 0, 0, 0, 0, 112, 255, 255, 12, 0, 0, 0, 0, 0, 32, 255, 255, 31, 0, 0, 0, 0, 0, 0, 253, 255, 111, 0, 0, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 0, 0, 244, 255, 255, 0, 0, 0, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 0, 0, 160, 255, 255, 9, 0, 0, 0, 0, 0, 96, 255, 255, 13, 0, 0, 0, 0, 0, 16, 255, 255, 47, 0, 0, 0, 0, 0, 0, 252, 255, 127, 0, 0, 0, 0, 0, 0, 247, 255, 207, 0, 0, 0, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 0, 0, 224, 255, 255, 5, 0, 0, 0, 0, 0, 144, 255, 255, 10 }; -/* ] */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_93[] = { 11, 39, 15, 1, 31, 215, 221, 221, 221, 221, 12, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 0, 0, 64, 255, 255, 15, 215, 221, 237, 255, 255, 15, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15, 248, 255, 255, 255, 255, 15 }; -/* ^ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_94[] = { 16, 12, 19, 1, 29, 0, 0, 224, 255, 255, 159, 0, 0, 0, 0, 244, 255, 255, 239, 0, 0, 0, 0, 250, 255, 255, 255, 4, 0, 0, 0, 255, 255, 255, 255, 10, 0, 0, 80, 255, 255, 253, 255, 31, 0, 0, 176, 255, 239, 244, 255, 111, 0, 0, 241, 255, 143, 208, 255, 207, 0, 0, 247, 255, 47, 112, 255, 255, 2, 0, 253, 255, 12, 32, 255, 255, 8, 48, 255, 255, 6, 0, 252, 255, 14, 144, 255, 255, 1, 0, 246, 255, 63, 224, 255, 175, 0, 0, 240, 255, 159 }; -/* _ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_95[] = { 19, 5, 17, 0, 0, 219, 221, 221, 221, 221, 221, 221, 221, 221, 2, 253, 255, 255, 255, 255, 255, 255, 255, 255, 3, 253, 255, 255, 255, 255, 255, 255, 255, 255, 3, 253, 255, 255, 255, 255, 255, 255, 255, 255, 3, 253, 255, 255, 255, 255, 255, 255, 255, 255, 3 }; -/* ` */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_96[] = { 10, 7, 12, 1, 31, 245, 255, 255, 1, 0, 128, 255, 255, 11, 0, 0, 250, 255, 95, 0, 0, 192, 255, 239, 1, 0, 16, 254, 255, 10, 0, 0, 243, 255, 95, 0, 0, 16, 17, 17 }; /* a */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_97[] = { 20, 23, 23, 1, 22, 0, 0, 0, 147, 237, 239, 140, 3, 0, 0, 0, 0, 161, 255, 255, 255, 255, 191, 2, 0, 0, 48, 255, 255, 255, 255, 255, 255, 62, 0, 0, 225, 255, 255, 255, 255, 255, 255, 239, 1, 0, 250, 255, 255, 108, 100, 252, 255, 255, 9, 0, 255, 255, 159, 0, 0, 176, 255, 255, 15, 64, 255, 255, 15, 0, 0, 32, 255, 255, 95, 16, 34, 34, 2, 0, 0, 0, 253, 255, 127, 0, 0, 0, 0, 0, 0, 0, 251, 255, 159, 0, 0, 96, 218, 254, 255, 255, 255, 255, 159, 0, 96, 255, 255, 255, 255, 255, 255, 255, 159, 0, 249, 255, 255, 255, 255, 255, 255, 255, 159, 80, 255, 255, 255, 255, 255, 255, 255, 255, 159, 208, 255, 255, 143, 2, 0, 0, 250, 255, 159, 242, 255, 255, 5, 0, 0, 0, 252, 255, 159, 244, 255, 255, 0, 0, 0, 0, 255, 255, 159, 244, 255, 255, 0, 0, 0, 112, 255, 255, 159, 242, 255, 255, 6, 0, 0, 244, 255, 255, 159, 224, 255, 255, 159, 52, 166, 255, 255, 255, 159, 80, 255, 255, 255, 255, 255, 255, 255, 255, 159, 0, 250, 255, 255, 255, 255, 255, 251, 255, 159, 0, 112, 255, 255, 255, 255, 111, 240, 255, 159, 0, 0, 129, 236, 223, 123, 0, 0, 0, 0 }; /* b */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_98[] = { 23, 30, 26, 2, 29, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 0, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 2, 96, 218, 239, 124, 1, 0, 0, 0, 240, 255, 255, 82, 254, 255, 255, 255, 143, 0, 0, 0, 240, 255, 255, 249, 255, 255, 255, 255, 255, 11, 0, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 207, 0, 0, 240, 255, 255, 255, 255, 239, 255, 255, 255, 255, 7, 0, 240, 255, 255, 255, 94, 1, 48, 252, 255, 255, 31, 0, 240, 255, 255, 223, 1, 0, 0, 144, 255, 255, 127, 0, 240, 255, 255, 63, 0, 0, 0, 0, 254, 255, 207, 0, 240, 255, 255, 11, 0, 0, 0, 0, 246, 255, 255, 0, 240, 255, 255, 7, 0, 0, 0, 0, 242, 255, 255, 3, 240, 255, 255, 5, 0, 0, 0, 0, 240, 255, 255, 4, 240, 255, 255, 3, 0, 0, 0, 0, 224, 255, 255, 5, 240, 255, 255, 5, 0, 0, 0, 0, 240, 255, 255, 4, 240, 255, 255, 7, 0, 0, 0, 0, 242, 255, 255, 3, 240, 255, 255, 11, 0, 0, 0, 0, 246, 255, 255, 0, 240, 255, 255, 63, 0, 0, 0, 0, 254, 255, 207, 0, 240, 255, 255, 207, 1, 0, 0, 144, 255, 255, 127, 0, 240, 255, 255, 255, 94, 1, 48, 252, 255, 255, 31, 0, 240, 255, 255, 255, 255, 239, 255, 255, 255, 255, 7, 0, 240, 255, 255, 255, 255, 255, 255, 255, 255, 207, 0, 0, 240, 255, 239, 250, 255, 255, 255, 255, 255, 28, 0, 0, 240, 255, 175, 112, 255, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 113, 219, 239, 124, 1, 0, 0, 0 }; /* c */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_99[] = { 22, 23, 24, 1, 22, 0, 0, 0, 48, 200, 254, 222, 73, 0, 0, 0, 0, 0, 48, 252, 255, 255, 255, 255, 61, 0, 0, 0, 0, 247, 255, 255, 255, 255, 255, 255, 6, 0, 0, 112, 255, 255, 255, 255, 255, 255, 255, 95, 0, 0, 244, 255, 255, 255, 239, 255, 255, 255, 255, 2, 0, 253, 255, 255, 94, 1, 48, 252, 255, 255, 10, 80, 255, 255, 207, 1, 0, 0, 160, 255, 255, 31, 176, 255, 255, 47, 0, 0, 0, 0, 254, 255, 111, 240, 255, 255, 8, 0, 0, 0, 0, 100, 102, 54, 242, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 244, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 243, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 242, 255, 255, 3, 0, 0, 0, 0, 0, 0, 0, 240, 255, 255, 8, 0, 0, 0, 0, 150, 153, 89, 176, 255, 255, 31, 0, 0, 0, 16, 255, 255, 95, 80, 255, 255, 207, 1, 0, 0, 176, 255, 255, 15, 0, 253, 255, 255, 94, 1, 48, 252, 255, 255, 10, 0, 244, 255, 255, 255, 239, 255, 255, 255, 255, 1, 0, 112, 255, 255, 255, 255, 255, 255, 255, 95, 0, 0, 0, 247, 255, 255, 255, 255, 255, 255, 6, 0, 0, 0, 48, 252, 255, 255, 255, 255, 61, 0, 0, 0, 0, 0, 64, 200, 254, 222, 73, 0, 0, 0 }; @@ -97,79 +35,75 @@ /* x */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_120[] = { 23, 21, 22, 0, 21, 160, 255, 255, 63, 0, 0, 0, 0, 252, 255, 255, 2, 16, 254, 255, 223, 0, 0, 0, 112, 255, 255, 111, 0, 0, 244, 255, 255, 9, 0, 0, 243, 255, 255, 11, 0, 0, 160, 255, 255, 79, 0, 0, 253, 255, 255, 1, 0, 0, 16, 254, 255, 239, 0, 128, 255, 255, 95, 0, 0, 0, 0, 244, 255, 255, 10, 243, 255, 255, 11, 0, 0, 0, 0, 144, 255, 255, 159, 253, 255, 239, 1, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 95, 0, 0, 0, 0, 0, 0, 244, 255, 255, 255, 255, 10, 0, 0, 0, 0, 0, 0, 144, 255, 255, 255, 239, 1, 0, 0, 0, 0, 0, 0, 64, 255, 255, 255, 191, 0, 0, 0, 0, 0, 0, 0, 208, 255, 255, 255, 255, 5, 0, 0, 0, 0, 0, 0, 249, 255, 255, 255, 255, 30, 0, 0, 0, 0, 0, 64, 255, 255, 255, 255, 255, 175, 0, 0, 0, 0, 0, 208, 255, 255, 14, 248, 255, 255, 5, 0, 0, 0, 0, 249, 255, 255, 4, 208, 255, 255, 30, 0, 0, 0, 48, 255, 255, 175, 0, 48, 255, 255, 175, 0, 0, 0, 208, 255, 255, 30, 0, 0, 249, 255, 255, 4, 0, 0, 248, 255, 255, 4, 0, 0, 208, 255, 255, 30, 0, 48, 255, 255, 175, 0, 0, 0, 48, 255, 255, 175, 0, 208, 255, 255, 30, 0, 0, 0, 0, 249, 255, 255, 4 }; /* y */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_121[] = { 23, 29, 22, 0, 21, 252, 255, 175, 0, 0, 0, 0, 0, 246, 255, 255, 1, 246, 255, 255, 1, 0, 0, 0, 0, 251, 255, 191, 0, 240, 255, 255, 6, 0, 0, 0, 16, 255, 255, 95, 0, 160, 255, 255, 13, 0, 0, 0, 112, 255, 255, 15, 0, 48, 255, 255, 63, 0, 0, 0, 208, 255, 255, 9, 0, 0, 253, 255, 159, 0, 0, 0, 242, 255, 255, 3, 0, 0, 247, 255, 255, 0, 0, 0, 248, 255, 239, 0, 0, 0, 241, 255, 255, 6, 0, 0, 254, 255, 143, 0, 0, 0, 160, 255, 255, 12, 0, 64, 255, 255, 47, 0, 0, 0, 64, 255, 255, 47, 0, 144, 255, 255, 12, 0, 0, 0, 0, 253, 255, 143, 0, 240, 255, 255, 6, 0, 0, 0, 0, 247, 255, 239, 0, 245, 255, 255, 1, 0, 0, 0, 0, 241, 255, 255, 5, 251, 255, 191, 0, 0, 0, 0, 0, 176, 255, 255, 27, 255, 255, 95, 0, 0, 0, 0, 0, 64, 255, 255, 255, 255, 255, 15, 0, 0, 0, 0, 0, 0, 254, 255, 255, 255, 255, 9, 0, 0, 0, 0, 0, 0, 248, 255, 255, 255, 255, 3, 0, 0, 0, 0, 0, 0, 242, 255, 255, 255, 223, 0, 0, 0, 0, 0, 0, 0, 176, 255, 255, 255, 143, 0, 0, 0, 0, 0, 0, 0, 80, 255, 255, 255, 47, 0, 0, 0, 0, 0, 0, 0, 0, 254, 255, 255, 12, 0, 0, 0, 0, 0, 0, 0, 0, 249, 255, 255, 6, 0, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 16, 253, 255, 191, 0, 0, 0, 0, 0, 0, 214, 221, 253, 255, 255, 95, 0, 0, 0, 0, 0, 0, 247, 255, 255, 255, 255, 14, 0, 0, 0, 0, 0, 0, 247, 255, 255, 255, 255, 6, 0, 0, 0, 0, 0, 0, 247, 255, 255, 255, 175, 0, 0, 0, 0, 0, 0, 0, 247, 255, 255, 189, 4, 0, 0, 0, 0, 0, 0 }; /* z */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_122[] = { 18, 21, 20, 1, 21, 248, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, 255, 255, 127, 215, 221, 221, 221, 221, 254, 255, 255, 111, 0, 0, 0, 0, 0, 252, 255, 255, 10, 0, 0, 0, 0, 176, 255, 255, 191, 0, 0, 0, 0, 0, 250, 255, 255, 12, 0, 0, 0, 0, 144, 255, 255, 223, 1, 0, 0, 0, 0, 247, 255, 255, 46, 0, 0, 0, 0, 96, 255, 255, 255, 2, 0, 0, 0, 0, 245, 255, 255, 63, 0, 0, 0, 0, 48, 255, 255, 255, 5, 0, 0, 0, 0, 242, 255, 255, 111, 0, 0, 0, 0, 32, 254, 255, 255, 7, 0, 0, 0, 0, 209, 255, 255, 159, 0, 0, 0, 0, 0, 250, 255, 255, 223, 221, 221, 221, 221, 157, 251, 255, 255, 255, 255, 255, 255, 255, 175, 251, 255, 255, 255, 255, 255, 255, 255, 175, 251, 255, 255, 255, 255, 255, 255, 255, 175, 251, 255, 255, 255, 255, 255, 255, 255, 175 }; -/* { */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_123[] = { 13, 39, 16, 2, 31, 0, 0, 0, 132, 219, 221, 3, 0, 0, 177, 255, 255, 255, 4, 0, 0, 252, 255, 255, 255, 4, 0, 96, 255, 255, 255, 255, 4, 0, 160, 255, 255, 255, 255, 4, 0, 208, 255, 255, 44, 0, 0, 0, 240, 255, 255, 5, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 242, 255, 255, 3, 0, 0, 48, 252, 255, 255, 1, 0, 0, 254, 255, 255, 143, 0, 0, 0, 254, 255, 255, 8, 0, 0, 0, 254, 255, 9, 0, 0, 0, 0, 254, 255, 191, 3, 0, 0, 0, 254, 255, 255, 79, 0, 0, 0, 183, 255, 255, 239, 0, 0, 0, 0, 246, 255, 255, 3, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 4, 0, 0, 0, 240, 255, 255, 5, 0, 0, 0, 224, 255, 255, 11, 0, 0, 0, 176, 255, 255, 255, 221, 3, 0, 112, 255, 255, 255, 255, 4, 0, 0, 253, 255, 255, 255, 4, 0, 0, 211, 255, 255, 255, 4, 0, 0, 0, 183, 253, 255, 4 }; -/* | */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_124[] = { 6, 40, 15, 5, 32, 0, 0, 0, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79, 255, 255, 79 }; -/* } */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_125[] = { 13, 39, 16, 1, 31, 215, 205, 122, 2, 0, 0, 0, 248, 255, 255, 143, 0, 0, 0, 248, 255, 255, 255, 7, 0, 0, 248, 255, 255, 255, 47, 0, 0, 248, 255, 255, 255, 111, 0, 0, 0, 64, 255, 255, 159, 0, 0, 0, 0, 250, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 247, 255, 239, 0, 0, 0, 0, 245, 255, 255, 41, 0, 0, 0, 192, 255, 255, 255, 10, 0, 0, 0, 251, 255, 255, 10, 0, 0, 0, 32, 253, 255, 10, 0, 0, 0, 163, 255, 255, 10, 0, 0, 96, 255, 255, 255, 10, 0, 0, 242, 255, 255, 159, 5, 0, 0, 247, 255, 255, 2, 0, 0, 0, 248, 255, 207, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 248, 255, 191, 0, 0, 0, 0, 249, 255, 191, 0, 0, 0, 16, 254, 255, 159, 0, 0, 215, 253, 255, 255, 127, 0, 0, 248, 255, 255, 255, 63, 0, 0, 248, 255, 255, 255, 9, 0, 0, 248, 255, 255, 191, 1, 0, 0, 248, 255, 173, 5, 0, 0, 0 }; -/* ~ */ static const uint8_t Font_TTSatoshi_DemiBold_42_glyph_126[] = { 23, 9, 25, 1, 16, 0, 0, 182, 254, 157, 1, 0, 0, 80, 102, 102, 0, 0, 193, 255, 255, 255, 78, 0, 0, 240, 255, 255, 0, 0, 251, 255, 255, 255, 255, 7, 0, 244, 255, 255, 0, 80, 255, 255, 255, 255, 255, 175, 84, 254, 255, 207, 0, 192, 255, 255, 255, 255, 255, 255, 255, 255, 255, 143, 0, 240, 255, 255, 92, 214, 255, 255, 255, 255, 255, 47, 0, 243, 255, 255, 1, 0, 251, 255, 255, 255, 255, 8, 0, 244, 255, 207, 0, 0, 112, 255, 255, 255, 159, 0, 0, 98, 102, 70, 0, 0, 0, 163, 254, 174, 4, 0, 0 }; /* ? */ const uint8_t Font_TTSatoshi_DemiBold_42_glyph_nonprintable[] = { 20, 30, 22, 1, 30, 255, 255, 223, 55, 1, 32, 132, 253, 255, 255, 255, 223, 4, 0, 0, 0, 0, 80, 254, 255, 255, 11, 0, 0, 0, 0, 0, 0, 193, 255, 207, 0, 0, 0, 0, 0, 0, 0, 16, 253, 63, 0, 0, 0, 0, 0, 0, 0, 0, 244, 11, 0, 0, 80, 235, 157, 1, 0, 0, 192, 6, 0, 0, 247, 255, 255, 63, 0, 0, 112, 2, 0, 0, 255, 255, 255, 207, 0, 0, 80, 35, 34, 82, 255, 255, 255, 255, 0, 0, 48, 255, 255, 255, 255, 255, 255, 255, 0, 0, 80, 255, 255, 255, 255, 255, 255, 175, 0, 0, 112, 255, 255, 255, 255, 255, 255, 10, 0, 0, 192, 255, 255, 255, 255, 255, 77, 0, 0, 0, 243, 255, 255, 255, 255, 143, 0, 0, 0, 16, 253, 255, 255, 255, 255, 9, 0, 0, 0, 211, 255, 255, 255, 255, 223, 0, 0, 0, 161, 255, 255, 255, 255, 255, 127, 0, 0, 48, 254, 255, 255, 255, 255, 255, 47, 0, 0, 241, 255, 255, 255, 255, 255, 255, 31, 0, 0, 248, 255, 255, 255, 255, 255, 255, 15, 0, 0, 251, 255, 255, 255, 255, 255, 255, 15, 0, 0, 252, 255, 255, 255, 255, 255, 255, 175, 170, 170, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 44, 34, 34, 249, 255, 255, 255, 255, 255, 255, 12, 0, 0, 249, 255, 255, 255, 255, 255, 255, 12, 0, 0, 249, 255, 255, 255, 255, 255, 255, 12, 0, 0, 249, 255, 255, 255, 255, 255, 255, 12, 0, 0, 249, 255, 255, 255, 255, 255, 255, 12, 0, 0, 249, 255, 255, 255 }; const uint8_t * const Font_TTSatoshi_DemiBold_42[126 + 1 - 32] = { Font_TTSatoshi_DemiBold_42_glyph_32, - Font_TTSatoshi_DemiBold_42_glyph_33, - Font_TTSatoshi_DemiBold_42_glyph_34, - Font_TTSatoshi_DemiBold_42_glyph_35, - Font_TTSatoshi_DemiBold_42_glyph_36, - Font_TTSatoshi_DemiBold_42_glyph_37, - Font_TTSatoshi_DemiBold_42_glyph_38, - Font_TTSatoshi_DemiBold_42_glyph_39, - Font_TTSatoshi_DemiBold_42_glyph_40, - Font_TTSatoshi_DemiBold_42_glyph_41, - Font_TTSatoshi_DemiBold_42_glyph_42, - Font_TTSatoshi_DemiBold_42_glyph_43, - Font_TTSatoshi_DemiBold_42_glyph_44, - Font_TTSatoshi_DemiBold_42_glyph_45, - Font_TTSatoshi_DemiBold_42_glyph_46, - Font_TTSatoshi_DemiBold_42_glyph_47, - Font_TTSatoshi_DemiBold_42_glyph_48, - Font_TTSatoshi_DemiBold_42_glyph_49, - Font_TTSatoshi_DemiBold_42_glyph_50, - Font_TTSatoshi_DemiBold_42_glyph_51, - Font_TTSatoshi_DemiBold_42_glyph_52, - Font_TTSatoshi_DemiBold_42_glyph_53, - Font_TTSatoshi_DemiBold_42_glyph_54, - Font_TTSatoshi_DemiBold_42_glyph_55, - Font_TTSatoshi_DemiBold_42_glyph_56, - Font_TTSatoshi_DemiBold_42_glyph_57, - Font_TTSatoshi_DemiBold_42_glyph_58, - Font_TTSatoshi_DemiBold_42_glyph_59, - Font_TTSatoshi_DemiBold_42_glyph_60, - Font_TTSatoshi_DemiBold_42_glyph_61, - Font_TTSatoshi_DemiBold_42_glyph_62, - Font_TTSatoshi_DemiBold_42_glyph_63, - Font_TTSatoshi_DemiBold_42_glyph_64, - Font_TTSatoshi_DemiBold_42_glyph_65, - Font_TTSatoshi_DemiBold_42_glyph_66, - Font_TTSatoshi_DemiBold_42_glyph_67, - Font_TTSatoshi_DemiBold_42_glyph_68, - Font_TTSatoshi_DemiBold_42_glyph_69, - Font_TTSatoshi_DemiBold_42_glyph_70, - Font_TTSatoshi_DemiBold_42_glyph_71, - Font_TTSatoshi_DemiBold_42_glyph_72, - Font_TTSatoshi_DemiBold_42_glyph_73, - Font_TTSatoshi_DemiBold_42_glyph_74, - Font_TTSatoshi_DemiBold_42_glyph_75, - Font_TTSatoshi_DemiBold_42_glyph_76, - Font_TTSatoshi_DemiBold_42_glyph_77, - Font_TTSatoshi_DemiBold_42_glyph_78, - Font_TTSatoshi_DemiBold_42_glyph_79, - Font_TTSatoshi_DemiBold_42_glyph_80, - Font_TTSatoshi_DemiBold_42_glyph_81, - Font_TTSatoshi_DemiBold_42_glyph_82, - Font_TTSatoshi_DemiBold_42_glyph_83, - Font_TTSatoshi_DemiBold_42_glyph_84, - Font_TTSatoshi_DemiBold_42_glyph_85, - Font_TTSatoshi_DemiBold_42_glyph_86, - Font_TTSatoshi_DemiBold_42_glyph_87, - Font_TTSatoshi_DemiBold_42_glyph_88, - Font_TTSatoshi_DemiBold_42_glyph_89, - Font_TTSatoshi_DemiBold_42_glyph_90, - Font_TTSatoshi_DemiBold_42_glyph_91, - Font_TTSatoshi_DemiBold_42_glyph_92, - Font_TTSatoshi_DemiBold_42_glyph_93, - Font_TTSatoshi_DemiBold_42_glyph_94, - Font_TTSatoshi_DemiBold_42_glyph_95, - Font_TTSatoshi_DemiBold_42_glyph_96, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_97, + Font_TTSatoshi_DemiBold_42_glyph_98, + Font_TTSatoshi_DemiBold_42_glyph_99, + Font_TTSatoshi_DemiBold_42_glyph_100, + Font_TTSatoshi_DemiBold_42_glyph_101, + Font_TTSatoshi_DemiBold_42_glyph_102, + Font_TTSatoshi_DemiBold_42_glyph_103, + Font_TTSatoshi_DemiBold_42_glyph_104, + Font_TTSatoshi_DemiBold_42_glyph_105, + Font_TTSatoshi_DemiBold_42_glyph_106, + Font_TTSatoshi_DemiBold_42_glyph_107, + Font_TTSatoshi_DemiBold_42_glyph_108, + Font_TTSatoshi_DemiBold_42_glyph_109, + Font_TTSatoshi_DemiBold_42_glyph_110, + Font_TTSatoshi_DemiBold_42_glyph_111, + Font_TTSatoshi_DemiBold_42_glyph_112, + Font_TTSatoshi_DemiBold_42_glyph_113, + Font_TTSatoshi_DemiBold_42_glyph_114, + Font_TTSatoshi_DemiBold_42_glyph_115, + Font_TTSatoshi_DemiBold_42_glyph_116, + Font_TTSatoshi_DemiBold_42_glyph_117, + Font_TTSatoshi_DemiBold_42_glyph_118, + Font_TTSatoshi_DemiBold_42_glyph_119, + Font_TTSatoshi_DemiBold_42_glyph_120, + Font_TTSatoshi_DemiBold_42_glyph_121, + Font_TTSatoshi_DemiBold_42_glyph_122, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, Font_TTSatoshi_DemiBold_42_glyph_97, Font_TTSatoshi_DemiBold_42_glyph_98, Font_TTSatoshi_DemiBold_42_glyph_99, @@ -196,8 +130,8 @@ const uint8_t * const Font_TTSatoshi_DemiBold_42[126 + 1 - 32] = { Font_TTSatoshi_DemiBold_42_glyph_120, Font_TTSatoshi_DemiBold_42_glyph_121, Font_TTSatoshi_DemiBold_42_glyph_122, - Font_TTSatoshi_DemiBold_42_glyph_123, - Font_TTSatoshi_DemiBold_42_glyph_124, - Font_TTSatoshi_DemiBold_42_glyph_125, - Font_TTSatoshi_DemiBold_42_glyph_126, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, + Font_TTSatoshi_DemiBold_42_glyph_nonprintable, }; diff --git a/core/embed/lib/fonts/font_ttsatoshi_demibold_42.h b/core/embed/lib/fonts/font_ttsatoshi_demibold_42.h index b69ede553e..6b737171e2 100644 --- a/core/embed/lib/fonts/font_ttsatoshi_demibold_42.h +++ b/core/embed/lib/fonts/font_ttsatoshi_demibold_42.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 4 diff --git a/core/embed/lib/fonts/font_unifont_bold_16.c b/core/embed/lib/fonts/font_unifont_bold_16.c index 975620b90d..666d0049dd 100644 --- a/core/embed/lib/fonts/font_unifont_bold_16.c +++ b/core/embed/lib/fonts/font_unifont_bold_16.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_unifont_bold_16.h b/core/embed/lib/fonts/font_unifont_bold_16.h index c28e0048d6..976e13c18d 100644 --- a/core/embed/lib/fonts/font_unifont_bold_16.h +++ b/core/embed/lib/fonts/font_unifont_bold_16.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 1 diff --git a/core/embed/lib/fonts/font_unifont_regular_16.c b/core/embed/lib/fonts/font_unifont_regular_16.c index 8ef83037cb..ecb7539457 100644 --- a/core/embed/lib/fonts/font_unifont_regular_16.c +++ b/core/embed/lib/fonts/font_unifont_regular_16.c @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include // clang-format off diff --git a/core/embed/lib/fonts/font_unifont_regular_16.h b/core/embed/lib/fonts/font_unifont_regular_16.h index f9a1ec2c1c..108b384d9a 100644 --- a/core/embed/lib/fonts/font_unifont_regular_16.h +++ b/core/embed/lib/fonts/font_unifont_regular_16.h @@ -1,3 +1,5 @@ +// This file is generated by core/tools/codegen/gen_font.py + #include #if TREZOR_FONT_BPP != 1 diff --git a/core/embed/lib/fonts/fonts.c b/core/embed/lib/fonts/fonts.c index 76b528ed9f..d2e6a73962 100644 --- a/core/embed/lib/fonts/fonts.c +++ b/core/embed/lib/fonts/fonts.c @@ -42,6 +42,14 @@ int font_height(int font) { case FONT_BOLD: return FONT_BOLD_HEIGHT; #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE + case FONT_NORMAL_UPPER: + return FONT_NORMAL_UPPER_HEIGHT; +#endif +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE + case FONT_BOLD_UPPER: + return FONT_BOLD_UPPER_HEIGHT; +#endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_HEIGHT; @@ -49,6 +57,10 @@ int font_height(int font) { #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_HEIGHT; +#endif +#ifdef TREZOR_FONT_SUB_ENABLE + case FONT_SUB: + return FONT_SUB_HEIGHT; #endif } return 0; @@ -68,6 +80,14 @@ int font_max_height(int font) { case FONT_BOLD: return FONT_BOLD_MAX_HEIGHT; #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE + case FONT_NORMAL_UPPER: + return FONT_NORMAL_UPPER_MAX_HEIGHT; +#endif +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE + case FONT_BOLD_UPPER: + return FONT_BOLD_UPPER_MAX_HEIGHT; +#endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_MAX_HEIGHT; @@ -75,6 +95,10 @@ int font_max_height(int font) { #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_MAX_HEIGHT; +#endif +#ifdef TREZOR_FONT_SUB_ENABLE + case FONT_SUB: + return FONT_SUB_MAX_HEIGHT; #endif } return 0; @@ -94,6 +118,14 @@ int font_baseline(int font) { case FONT_BOLD: return FONT_BOLD_BASELINE; #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE + case FONT_NORMAL_UPPER: + return FONT_NORMAL_UPPER_BASELINE; +#endif +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE + case FONT_BOLD_UPPER: + return FONT_BOLD_UPPER_BASELINE; +#endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_BASELINE; @@ -101,6 +133,10 @@ int font_baseline(int font) { #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_BASELINE; +#endif +#ifdef TREZOR_FONT_SUB_ENABLE + case FONT_SUB: + return FONT_SUB_BASELINE; #endif } return 0; @@ -115,7 +151,7 @@ font_glyph_iter_t font_glyph_iter_init(const int font, const uint8_t *text, }; } -#define IS_UTF8_CONTINUE(c) (((c)&0b11000000) == 0b10000000) +#define IS_UTF8_CONTINUE(c) (((c) & 0b11000000) == 0b10000000) static uint16_t next_utf8_codepoint(font_glyph_iter_t *iter) { uint16_t out; @@ -192,6 +228,14 @@ const uint8_t *font_nonprintable_glyph(int font) { case FONT_BOLD: return NONPRINTABLE_GLYPH(FONT_BOLD_DATA); #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE + case FONT_NORMAL_UPPER: + return NONPRINTABLE_GLYPH(FONT_NORMAL_UPPER_DATA); +#endif +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE + case FONT_BOLD_UPPER: + return NONPRINTABLE_GLYPH(FONT_BOLD_UPPER_DATA); +#endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return NONPRINTABLE_GLYPH(FONT_MONO_DATA); @@ -199,6 +243,10 @@ const uint8_t *font_nonprintable_glyph(int font) { #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return NONPRINTABLE_GLYPH(FONT_BIG_DATA); +#endif +#ifdef TREZOR_FONT_SUB_ENABLE + case FONT_SUB: + return NONPRINTABLE_GLYPH(FONT_SUB_DATA); #endif default: return NULL; @@ -233,6 +281,14 @@ const uint8_t *font_get_glyph(int font, uint16_t c) { case FONT_BOLD: return FONT_BOLD_DATA[c - ' ']; #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE + case FONT_NORMAL_UPPER: + return FONT_NORMAL_UPPER_DATA[c - ' ']; +#endif +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE + case FONT_BOLD_UPPER: + return FONT_BOLD_UPPER_DATA[c - ' ']; +#endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_DATA[c - ' ']; @@ -240,6 +296,10 @@ const uint8_t *font_get_glyph(int font, uint16_t c) { #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_DATA[c - ' ']; +#endif +#ifdef TREZOR_FONT_SUB_ENABLE + case FONT_SUB: + return FONT_SUB_DATA[c - ' ']; #endif } return 0; diff --git a/core/embed/lib/fonts/fonts.h b/core/embed/lib/fonts/fonts.h index 108dd91999..2e4405e903 100644 --- a/core/embed/lib/fonts/fonts.h +++ b/core/embed/lib/fonts/fonts.h @@ -64,6 +64,15 @@ FONT_DEFINE(TREZOR_FONT_DEMIBOLD_ENABLE, _BASELINE) #endif +#ifdef TREZOR_FONT_SUB_ENABLE +#include TREZOR_FONT_SUB_INCLUDE +#define FONT_SUB (-8) +#define FONT_SUB_DATA TREZOR_FONT_SUB_ENABLE +#define FONT_SUB_HEIGHT FONT_DEFINE(TREZOR_FONT_SUB_ENABLE, _HEIGHT) +#define FONT_SUB_MAX_HEIGHT FONT_DEFINE(TREZOR_FONT_SUB_ENABLE, _MAX_HEIGHT) +#define FONT_SUB_BASELINE FONT_DEFINE(TREZOR_FONT_SUB_ENABLE, _BASELINE) +#endif + #ifdef TREZOR_FONT_MONO_ENABLE #include TREZOR_FONT_MONO_INCLUDE #define FONT_MONO (-3) @@ -82,6 +91,30 @@ #define FONT_BOLD_BASELINE FONT_DEFINE(TREZOR_FONT_BOLD_ENABLE, _BASELINE) #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE +#include TREZOR_FONT_NORMAL_UPPER_INCLUDE +#define FONT_NORMAL_UPPER (-6) +#define FONT_NORMAL_UPPER_DATA TREZOR_FONT_NORMAL_UPPER_ENABLE +#define FONT_NORMAL_UPPER_HEIGHT \ + FONT_DEFINE(TREZOR_FONT_NORMAL_UPPER_ENABLE, _HEIGHT) +#define FONT_NORMAL_UPPER_MAX_HEIGHT \ + FONT_DEFINE(TREZOR_FONT_NORMAL_UPPER_ENABLE, _MAX_HEIGHT) +#define FONT_NORMAL_UPPER_BASELINE \ + FONT_DEFINE(TREZOR_FONT_NORMAL_UPPER_ENABLE, _BASELINE) +#endif + +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE +#include TREZOR_FONT_BOLD_UPPER_INCLUDE +#define FONT_BOLD_UPPER (-7) +#define FONT_BOLD_UPPER_DATA TREZOR_FONT_BOLD_UPPER_ENABLE +#define FONT_BOLD_UPPER_HEIGHT \ + FONT_DEFINE(TREZOR_FONT_BOLD_UPPER_ENABLE, _HEIGHT) +#define FONT_BOLD_UPPER_MAX_HEIGHT \ + FONT_DEFINE(TREZOR_FONT_BOLD_UPPER_ENABLE, _MAX_HEIGHT) +#define FONT_BOLD_UPPER_BASELINE \ + FONT_DEFINE(TREZOR_FONT_BOLD_UPPER_ENABLE, _BASELINE) +#endif + #define MAX_FONT_H(A, B) ((A) > (B) ? (A) : (B)) #define FONT_MAX_HEIGHT_1 0 @@ -110,10 +143,30 @@ #define FONT_MAX_HEIGHT_5 FONT_MAX_HEIGHT_4 #endif +#ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE +#define FONT_MAX_HEIGHT_6 \ + MAX_FONT_H(FONT_NORMAL_UPPER_MAX_HEIGHT, FONT_MAX_HEIGHT_5) +#else +#define FONT_MAX_HEIGHT_6 FONT_MAX_HEIGHT_5 +#endif + +#ifdef TREZOR_FONT_BOLD_UPPER_ENABLE +#define FONT_MAX_HEIGHT_7 \ + MAX_FONT_H(FONT_BOLD_UPPER_MAX_HEIGHT, FONT_MAX_HEIGHT_6) +#else +#define FONT_MAX_HEIGHT_7 FONT_MAX_HEIGHT_6 +#endif + +#ifdef TREZOR_FONT_SUB_ENABLE +#define FONT_MAX_HEIGHT_8 MAX_FONT_H(FONT_SUB_MAX_HEIGHT, FONT_MAX_HEIGHT_7) +#else +#define FONT_MAX_HEIGHT_8 FONT_MAX_HEIGHT_7 +#endif + #ifdef TREZOR_FONT_MONO_ENABLE -#define FONT_MAX_HEIGHT MAX_FONT_H(FONT_MONO_MAX_HEIGHT, FONT_MAX_HEIGHT_5) +#define FONT_MAX_HEIGHT MAX_FONT_H(FONT_MONO_MAX_HEIGHT, FONT_MAX_HEIGHT_8) #else -#define FONT_MAX_HEIGHT FONT_MAX_HEIGHT_5 +#define FONT_MAX_HEIGHT FONT_MAX_HEIGHT_8 #endif int font_height(int font); diff --git a/core/embed/lib/gfx_bitblt.h b/core/embed/lib/gfx_bitblt.h new file mode 100644 index 0000000000..f897d933b5 --- /dev/null +++ b/core/embed/lib/gfx_bitblt.h @@ -0,0 +1,126 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GFX_BITBLT_H +#define GFX_BITBLT_H + +#include +#include + +#include "gfx_color.h" + +// These module provides low-level bit block transfer (bitblt) +// operations on different bitmap/framebuffer types. +// +// `fill` - fills a rectangle with a solid color (with an optional +// alpha, allowing color blending). +// +// `copy` - copies a bitmap or part of it to the destination bitmap. +// +// `blend` - blends a bitmap with a 1- or 4-bit alpha channel to the +// destination using background and foreground colors. +// +// These operations might be accelerated using DMA2D (ChromART accelerator) +// on the STM32 platform. + +// Represents a set of parameters for a bit block transfer operation. +typedef struct { + // Pointer to the destination bitmap's first row + void* dst_row; + // Number of bytes per line in the destination bitmap + uint16_t dst_stride; + // X-coordinate of the top-left corner inside the destination + uint16_t dst_x; + // Y-coordinate of the top-left corner inside the destination + uint16_t dst_y; + // Height of the filled/copied/blended area + uint16_t height; + // Width of the filled/copied/blended area + uint16_t width; + + // Pointer to the source bitmap's first row + // (unused for fill operations) + void* src_row; + // Number of bytes per line in the source bitmap + // (unused for fill operations) + uint16_t src_stride; + // X-coordinate of the origin in the source bitmap + // (unused for fill operations) + uint16_t src_x; + // Y-coordinate of the origin in the source bitmap + // (unused for fill operations) + uint16_t src_y; + + // Foreground color used when copying/blending/filling + gfx_color_t src_fg; + // Background color used when copying mono bitmaps + gfx_color_t src_bg; + // Alpha value for fill operation (255 => normal fill, 0 => noop) + uint8_t src_alpha; + +} gfx_bitblt_t; + +// Functions for RGB565 bitmap/framebuffer + +// Fills a rectangle with a solid color +void gfx_rgb565_fill(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 1-bit alpha channel) +void gfx_rgb565_copy_mono1p(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 4-bit alpha channel) +void gfx_rgb565_copy_mono4(const gfx_bitblt_t* bb); +// Copies an RGB565 bitmap +void gfx_rgb565_copy_rgb565(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 4-bit alpha channel) +// with the destination bitmap +void gfx_rgb565_blend_mono4(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 8-bit alpha channel) +// with the destination bitmap +void gfx_rgb565_blend_mono8(const gfx_bitblt_t* bb); + +// Functions for RGBA8888 bitmap/framebuffer +void gfx_rgba8888_fill(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 1-bit alpha channel) +void gfx_rgba8888_copy_mono1p(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 4-bit alpha channel) +void gfx_rgba8888_copy_mono4(const gfx_bitblt_t* bb); +// Copies an RGB565 bitmap +void gfx_rgba8888_copy_rgb565(const gfx_bitblt_t* bb); +// Copies an RGBA8888 bitmap +void gfx_rgba8888_copy_rgba8888(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 4-bit alpha channel) +// with the destination bitmap +void gfx_rgba8888_blend_mono4(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 8-bit alpha channel) +// with the destination bitmap +void gfx_rgba8888_blend_mono8(const gfx_bitblt_t* bb); + +// Functions for Mono8 bitmap/framebuffer +void gfx_mono8_fill(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 1-bit alpha channel) +void gfx_mono8_copy_mono1p(const gfx_bitblt_t* bb); +// Copies a mono bitmap (with 4-bit alpha channel) +void gfx_mono8_copy_mono4(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 1-bit alpha channel) +// with the destination bitmap +void gfx_mono8_blend_mono1p(const gfx_bitblt_t* bb); +// Blends a mono bitmap (with 4-bit alpha channel) +// with the destination bitmap +void gfx_mono8_blend_mono4(const gfx_bitblt_t* bb); + +#endif // GFX_BITBLT_H diff --git a/core/embed/lib/gfx_bitblt_mono8.c b/core/embed/lib/gfx_bitblt_mono8.c new file mode 100644 index 0000000000..c1cb85d660 --- /dev/null +++ b/core/embed/lib/gfx_bitblt_mono8.c @@ -0,0 +1,111 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gfx_bitblt.h" + +void gfx_mono8_fill(const gfx_bitblt_t* bb) { + uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x; + uint16_t height = bb->height; + + uint8_t fg = gfx_color_lum(bb->src_fg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = fg; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + } +} + +void gfx_mono8_copy_mono1p(const gfx_bitblt_t* bb) { + uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x; + uint8_t* src = (uint8_t*)bb->src_row; + uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x; + uint16_t height = bb->height; + + uint8_t fg = gfx_color_lum(bb->src_fg); + uint8_t bg = gfx_color_lum(bb->src_bg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t mask = 1 << (7 - ((src_ofs + x) & 7)); + uint8_t data = src[(src_ofs + x) / 8]; + dst_ptr[x] = (data & mask) ? fg : bg; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ofs += bb->src_stride; + } +} + +void gfx_mono8_copy_mono4(const gfx_bitblt_t* bb) { + uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + uint8_t fg = gfx_color_lum(bb->src_fg); + uint8_t bg = gfx_color_lum(bb->src_bg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t src_data = src_row[(x + bb->src_x) / 2]; + uint8_t src_lum = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0xF; + dst_ptr[x] = (fg * src_lum + bg * (15 - src_lum)) / 15; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } +} + +void gfx_mono8_blend_mono1p(const gfx_bitblt_t* bb) { + uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x; + uint8_t* src = (uint8_t*)bb->src_row; + uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x; + uint16_t height = bb->height; + + uint8_t fg = gfx_color_lum(bb->src_fg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t mask = 1 << (7 - ((src_ofs + x) & 7)); + uint8_t data = src[(src_ofs + x) / 8]; + dst_ptr[x] = (data & mask) ? fg : dst_ptr[x]; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ofs += bb->src_stride; + } +} + +void gfx_mono8_blend_mono4(const gfx_bitblt_t* bb) { + uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + uint8_t fg = gfx_color_lum(bb->src_fg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t src_data = src_row[(x + bb->src_x) / 2]; + uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F; + src_alpha = src_alpha * bb->src_alpha / 15; + dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (255 - src_alpha)); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } +} diff --git a/core/embed/lib/gfx_bitblt_rgb565.c b/core/embed/lib/gfx_bitblt_rgb565.c new file mode 100644 index 0000000000..8648f5267a --- /dev/null +++ b/core/embed/lib/gfx_bitblt_rgb565.c @@ -0,0 +1,158 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gfx_bitblt.h" + +#if USE_DMA2D +#include "dma2d_bitblt.h" +#endif + +void gfx_rgb565_fill(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgb565_fill(bb)) +#endif + { + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint16_t height = bb->height; + + if (bb->src_alpha == 255) { + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = bb->src_fg; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + } + } else { + uint8_t alpha = bb->src_alpha; + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = gfx_color16_blend_a8(bb->src_fg, dst_ptr[x], alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + } + } + } +} + +void gfx_rgb565_copy_mono1p(const gfx_bitblt_t* bb) { + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint8_t* src = (uint8_t*)bb->src_row; + uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x; + uint16_t height = bb->height; + + uint16_t fg = gfx_color_to_color16(bb->src_fg); + uint16_t bg = gfx_color_to_color16(bb->src_bg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t mask = 1 << (7 - ((src_ofs + x) & 7)); + uint8_t data = src[(src_ofs + x) / 8]; + dst_ptr[x] = (data & mask) ? fg : bg; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ofs += bb->src_stride; + } +} + +void gfx_rgb565_copy_mono4(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgb565_copy_mono4(bb)) +#endif + { + const gfx_color16_t* gradient = + gfx_color16_gradient_a4(bb->src_fg, bb->src_bg); + + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_data = src_row[(x + bb->src_x) / 2]; + uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF; + dst_ptr[x] = gradient[fg_lum]; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } + } +} + +void gfx_rgb565_copy_rgb565(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgb565_copy_rgb565(bb)) +#endif + { + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = src_ptr[x]; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ptr += bb->src_stride / sizeof(*src_ptr); + } + } +} + +void gfx_rgb565_blend_mono4(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgb565_blend_mono4(bb)) +#endif + { + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_data = src_row[(x + bb->src_x) / 2]; + uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F; + fg_alpha = fg_alpha * bb->src_alpha / 15; + dst_ptr[x] = gfx_color16_blend_a8( + bb->src_fg, gfx_color16_to_color(dst_ptr[x]), fg_alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } + } +} + +void gfx_rgb565_blend_mono8(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgb565_blend_mono8(bb)) +#endif + { + uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x; + uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_alpha = src_ptr[x]; + dst_ptr[x] = gfx_color16_blend_a8( + bb->src_fg, gfx_color16_to_color(dst_ptr[x]), fg_alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ptr += bb->src_stride / sizeof(*src_ptr); + } + } +} diff --git a/core/embed/lib/gfx_bitblt_rgba8888.c b/core/embed/lib/gfx_bitblt_rgba8888.c new file mode 100644 index 0000000000..1eab15525c --- /dev/null +++ b/core/embed/lib/gfx_bitblt_rgba8888.c @@ -0,0 +1,178 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gfx_bitblt.h" + +#if USE_DMA2D +#include "dma2d_bitblt.h" +#endif + +void gfx_rgba8888_fill(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_fill(bb)) +#endif + { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint16_t height = bb->height; + + if (bb->src_alpha == 255) { + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = gfx_color_to_color32(bb->src_fg); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + } + } else { + uint8_t alpha = bb->src_alpha; + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = gfx_color32_blend_a8( + bb->src_fg, gfx_color32_to_color(dst_ptr[x]), alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + } + } + } +} + +void gfx_rgba8888_copy_mono1p(const gfx_bitblt_t* bb) { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint8_t* src = (uint8_t*)bb->src_row; + uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x; + uint16_t height = bb->height; + + uint32_t fg = gfx_color_to_color32(bb->src_fg); + uint32_t bg = gfx_color_to_color32(bb->src_bg); + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t mask = 1 << (7 - ((src_ofs + x) & 7)); + uint8_t data = src[(src_ofs + x) / 8]; + dst_ptr[x] = (data & mask) ? fg : bg; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ofs += bb->src_stride; + } +} + +void gfx_rgba8888_copy_mono4(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_copy_mono4(bb)) +#endif + { + const gfx_color32_t* gradient = + gfx_color32_gradient_a4(bb->src_fg, bb->src_bg); + + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_data = src_row[(x + bb->src_x) / 2]; + uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF; + dst_ptr[x] = gradient[fg_lum]; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } + } +} + +void gfx_rgba8888_copy_rgb565(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_copy_rgb565(bb)) +#endif + { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = gfx_color16_to_color32(src_ptr[x]); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ptr += bb->src_stride / sizeof(*src_ptr); + } + } +} + +void gfx_rgba8888_copy_rgba8888(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_copy_rgba8888(bb)) +#endif + { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint32_t* src_ptr = (uint32_t*)bb->src_row + bb->src_x; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + dst_ptr[x] = src_ptr[x]; + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ptr += bb->src_stride / sizeof(*src_ptr); + } + } +} + +void gfx_rgba8888_blend_mono4(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_blend_mono4(bb)) +#endif + { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint8_t* src_row = (uint8_t*)bb->src_row; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_data = src_row[(x + bb->src_x) / 2]; + uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F; + fg_alpha = fg_alpha * bb->src_alpha / 15; + dst_ptr[x] = gfx_color32_blend_a8( + bb->src_fg, gfx_color32_to_color(dst_ptr[x]), fg_alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_row += bb->src_stride / sizeof(*src_row); + } + } +} + +void gfx_rgba8888_blend_mono8(const gfx_bitblt_t* bb) { +#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR) + if (!dma2d_rgba8888_blend_mono8(bb)) +#endif + { + uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x; + uint8_t* src_ptr = (uint8_t*)bb->src_row + bb->src_x; + uint16_t height = bb->height; + + while (height-- > 0) { + for (int x = 0; x < bb->width; x++) { + uint8_t fg_alpha = src_ptr[x]; + dst_ptr[x] = gfx_color32_blend_a8( + bb->src_fg, gfx_color32_to_color(dst_ptr[x]), fg_alpha); + } + dst_ptr += bb->dst_stride / sizeof(*dst_ptr); + src_ptr += bb->src_stride / sizeof(*src_ptr); + } + } +} diff --git a/core/embed/lib/gfx_color.c b/core/embed/lib/gfx_color.c new file mode 100644 index 0000000000..429446e2ae --- /dev/null +++ b/core/embed/lib/gfx_color.c @@ -0,0 +1,49 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gfx_color.h" +#include "colors.h" + +const gfx_color16_t* gfx_color16_gradient_a4(gfx_color_t fg_color, + gfx_color_t bg_color) { + static gfx_color16_t cache[16] = {0}; + + if (gfx_color_to_color16(bg_color) != cache[0] || + gfx_color_to_color16(fg_color) != cache[15]) { + for (int alpha = 0; alpha < 16; alpha++) { + cache[alpha] = gfx_color16_blend_a4(fg_color, bg_color, alpha); + } + } + + return cache; +} + +const gfx_color32_t* gfx_color32_gradient_a4(gfx_color_t fg_color, + gfx_color_t bg_color) { + static gfx_color32_t cache[16] = {0}; + + if (bg_color != gfx_color32_to_color(cache[0]) || + fg_color != gfx_color32_to_color(cache[15])) { + for (int alpha = 0; alpha < 16; alpha++) { + cache[alpha] = gfx_color32_blend_a4(fg_color, bg_color, alpha); + } + } + + return cache; +} diff --git a/core/embed/lib/gfx_color.h b/core/embed/lib/gfx_color.h new file mode 100644 index 0000000000..5cbfd9f1ca --- /dev/null +++ b/core/embed/lib/gfx_color.h @@ -0,0 +1,365 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GFX_COLOR_H +#define GFX_COLOR_H + +#include + +#ifdef UI_COLOR_32BIT +#define GFX_COLOR_32BIT +#else +#define GFX_COLOR_16BIT +#endif + +// Color in RGB565 format +// +// |15 8 | 7 0| +// |---------------------------------| +// |r r r r r g g g | g g g b b b b b| +// |---------------------------------| + +typedef uint16_t gfx_color16_t; + +// Color in RGBA8888 format +// +// |31 24 |23 16 |15 8 | 7 0 | +// |----------------------------------------------------------------------| +// |a a a a a a a a | r r r r r r r r | g g g g g g g g | b b b b b b b b | +// |----------------------------------------------------------------------| +// + +typedef uint32_t gfx_color32_t; + +#ifdef GFX_COLOR_16BIT +#define gfx_color_t gfx_color16_t +#define gfx_color_to_color16(c) (c) +#define gfx_color16_to_color(c) (c) +#define gfx_color_to_color32(c) (gfx_color16_to_color32(c)) +#define gfx_color32_to_color(c) (gfx_color32_to_color16(c)) +#define gfx_color_lum(c) (gfx_color16_lum(c)) +#elif defined GFX_COLOR_32BIT +#define gfx_color_t gfx_color32_t +#define gfx_color_to_color16(c) (gfx_color32_to_color16(c)) +#define gfx_color16_to_color(c) (gfx_color16_to_color32(c)) +#define gfx_color_to_color32(c) (c) +#define gfx_color32_to_color(c) (c) +#define gfx_color_lum(c) (gfx_color32_lum(c)) +#else +#error "GFX_COLOR_16BIT/32BIT not specified" +#endif + +// Extracts red component from gfx_color16_t and converts it to 8-bit value +#define gfx_color16_to_r(c) ((((c) & 0xF800) >> 8) | (((c) & 0xF800) >> 13)) +// Extracts green component from gfx_color16_t and converts it to 8-bit value +#define gfx_color16_to_g(c) ((((c) & 0x07E0) >> 3) | (((c) & 0x07E0) >> 9)) +// Extracts blue component from gfx_color16_t and converts it to 8-bit value +#define gfx_color16_to_b(c) ((((c) & 0x001F) << 3) | (((c) & 0x001F) >> 2)) + +// Extracts red component from gfx_color32_t +#define gfx_color32_to_r(c) (((c) & 0x00FF0000) >> 16) +// Extracts green component from gfx_color32_t +#define gfx_color32_to_g(c) (((c) & 0x0000FF00) >> 8) +// Extracts blue component from gfx_color32_t +#define gfx_color32_to_b(c) (((c) & 0x000000FF) >> 0) +// Extracts alpha component from gfx_color32_t +#define gfx_color32_to_a(c) (((c) & 0xFF000000) >> 24) + +// 4-bit linear interpolation between `fg` and `bg` +#define a4_lerp(fg, bg, alpha) (((fg) * (alpha) + ((bg) * (15 - (alpha)))) / 15) +// 8-bit linear interpolation between `fg` and `bg` +#define a8_lerp(fg, bg, alpha) \ + (((fg) * (alpha) + ((bg) * (255 - (alpha)))) / 255) + +// Constructs a 16-bit color from the given red (r), +// green (g), and blue (b) values in the range 0..255 +static inline gfx_color16_t gfx_color16_rgb(uint8_t r, uint8_t g, uint8_t b) { + return ((r & 0xF8U) << 8) | ((g & 0xFCU) << 3) | ((b & 0xF8U) >> 3); +} + +// Constructs a 32-bit color from the given red (r), +// green (g), and blue (b) values in the range 0..255. +// Alpha is set to 255. +static inline gfx_color32_t gfx_color32_rgb(uint8_t r, uint8_t g, uint8_t b) { + return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +// Constructs a 32-bit color from the given red (r), +// green (g), blue (b) and alhpa (a) values in the range 0..255. +static inline gfx_color32_t gfx_color32_rgba(uint8_t r, uint8_t g, uint8_t b, + uint8_t a) { + return (a << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; +} + +// Converts a 16-bit color to a 32-bit color; alpha is set to 255 +static inline gfx_color32_t gfx_color16_to_color32(gfx_color16_t color) { + uint32_t r = gfx_color16_to_r(color); + uint32_t g = gfx_color16_to_g(color); + uint32_t b = gfx_color16_to_b(color); + + return gfx_color32_rgb(r, g, b); +} + +// Converts 32-bit color to 16-bit color, alpha is ignored +static inline gfx_color16_t gfx_color32_to_color16(gfx_color32_t color) { + uint16_t r = (color & 0x00F80000) >> 8; + uint16_t g = (color & 0x0000FC00) >> 5; + uint16_t b = (color & 0x000000F8) >> 3; + + return r | g | b; +} + +// Converts 16-bit color into luminance (ranging from 0 to 255) +static inline uint8_t gfx_color16_lum(gfx_color16_t color) { + uint32_t r = gfx_color16_to_r(color); + uint32_t g = gfx_color16_to_g(color); + uint32_t b = gfx_color16_to_b(color); + + return (r + g + b) / 3; +} + +// Converts 32-bit color into luminance (ranging from 0 to 255) +static inline uint8_t gfx_color32_lum(gfx_color32_t color) { + uint32_t r = gfx_color32_to_r(color); + uint32_t g = gfx_color32_to_g(color); + uint32_t b = gfx_color32_to_b(color); + + return (r + g + b) / 3; +} + +#ifdef GFX_COLOR_16BIT +// Blends foreground and background colors with 4-bit alpha +// +// Returns a color in 16-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 15, the function returns the foreground color +static inline gfx_color16_t gfx_color16_blend_a4(gfx_color16_t fg, + gfx_color16_t bg, + uint8_t alpha) { + uint16_t fg_r = (fg & 0xF800) >> 11; + uint16_t bg_r = (bg & 0xF800) >> 11; + uint16_t r = a4_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = (fg & 0x07E0) >> 5; + uint16_t bg_g = (bg & 0x07E0) >> 5; + uint16_t g = a4_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = (fg & 0x001F) >> 0; + uint16_t bg_b = (bg & 0x001F) >> 0; + uint16_t b = a4_lerp(fg_b, bg_b, alpha); + + return (r << 11) | (g << 5) | b; +} + +// Blends foreground and background colors with 8-bit alpha +// +// Returns a color in 16-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 15, the function returns the foreground color +static inline gfx_color16_t gfx_color16_blend_a8(gfx_color16_t fg, + gfx_color16_t bg, + uint8_t alpha) { + uint16_t fg_r = (fg & 0xF800) >> 11; + uint16_t bg_r = (bg & 0xF800) >> 11; + uint16_t r = a8_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = (fg & 0x07E0) >> 5; + uint16_t bg_g = (bg & 0x07E0) >> 5; + uint16_t g = a8_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = (fg & 0x001F) >> 0; + uint16_t bg_b = (bg & 0x001F) >> 0; + uint16_t b = a8_lerp(fg_b, bg_b, alpha); + + return (r << 11) | (g << 5) | b; +} + +// Blends foreground and background colors with 4-bit alpha +// +// Returns a color in 32-bit format +// +// If alpha is 0, the function returns the background color +// If alpha is 15, the function returns the foreground color +static inline gfx_color32_t gfx_color32_blend_a4(gfx_color16_t fg, + gfx_color16_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color16_to_r(fg); + uint16_t bg_r = gfx_color16_to_r(bg); + uint16_t r = a4_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color16_to_g(fg); + uint16_t bg_g = gfx_color16_to_g(bg); + uint16_t g = a4_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color16_to_b(fg); + uint16_t bg_b = gfx_color16_to_b(bg); + uint16_t b = a4_lerp(fg_b, bg_b, alpha); + + return gfx_color32_rgb(r, g, b); +} + +// Blends foreground and background colors with 8-bit alpha +// +// Returns a color in 32-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 255, the function returns the foreground color +static inline gfx_color32_t gfx_color32_blend_a8(gfx_color16_t fg, + gfx_color16_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color16_to_r(fg); + uint16_t bg_r = gfx_color16_to_r(bg); + uint16_t r = a8_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color16_to_g(fg); + uint16_t bg_g = gfx_color16_to_g(bg); + uint16_t g = a8_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color16_to_b(fg); + uint16_t bg_b = gfx_color16_to_b(bg); + uint16_t b = a8_lerp(fg_b, bg_b, alpha); + + return gfx_color32_rgb(r, g, b); +} + +#elif defined GFX_COLOR_32BIT + +// Blends foreground and background colors with 4-bit alpha +// +// Returns a color in 16-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 15, the function returns the foreground color +static inline gfx_color16_t gfx_color16_blend_a4(gfx_color32_t fg, + gfx_color32_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color32_to_r(fg); + uint16_t bg_r = gfx_color32_to_r(bg); + uint16_t r = a4_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color32_to_g(fg); + uint16_t bg_g = gfx_color32_to_g(bg); + uint16_t g = a4_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color32_to_b(fg); + uint16_t bg_b = gfx_color32_to_b(bg); + uint16_t b = a4_lerp(fg_b, bg_b, alpha); + + return gfx_color16_rgb(r, g, b); +} + +// Blends foreground and background colors with 8-bit alpha +// +// Returns a color in 16-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 255, the function returns the foreground color +static inline gfx_color16_t gfx_color16_blend_a8(gfx_color32_t fg, + gfx_color32_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color32_to_r(fg); + uint16_t bg_r = gfx_color32_to_r(bg); + uint16_t r = a8_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color32_to_g(fg); + uint16_t bg_g = gfx_color32_to_g(bg); + uint16_t g = a8_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color32_to_b(fg); + uint16_t bg_b = gfx_color32_to_b(bg); + uint16_t b = g = a8_lerp(fg_b, bg_b, alpha); + + return gfx_color16_rgb(r, g, b); +} + +// Blends foreground and background colors with 4-bit alpha +// +// Returns a color in 32-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 15, the function returns the foreground color +static inline gfx_color32_t gfx_color32_blend_a4(gfx_color32_t fg, + gfx_color32_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color32_to_r(fg); + uint16_t bg_r = gfx_color32_to_r(bg); + uint16_t r = a4_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color32_to_g(fg); + uint16_t bg_g = gfx_color32_to_g(bg); + uint16_t g = a4_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color32_to_b(fg); + uint16_t bg_b = gfx_color32_to_b(bg); + uint16_t b = a4_lerp(fg_b, bg_b, alpha); + + return gfx_color32_rgb(r, g, b); +} + +// Blends foreground and background colors with 8-bit alpha +// +// Returns a color in 32-bit format +// +// If `alpha` is 0, the function returns the background color +// If `alpha` is 15, the function returns the foreground color +static inline gfx_color32_t gfx_color32_blend_a8(gfx_color32_t fg, + gfx_color32_t bg, + uint8_t alpha) { + uint16_t fg_r = gfx_color32_to_r(fg); + uint16_t bg_r = gfx_color32_to_r(bg); + uint16_t r = a8_lerp(fg_r, bg_r, alpha); + + uint16_t fg_g = gfx_color32_to_g(fg); + uint16_t bg_g = gfx_color32_to_g(bg); + uint16_t g = a8_lerp(fg_g, bg_g, alpha); + + uint16_t fg_b = gfx_color32_to_b(fg); + uint16_t bg_b = gfx_color32_to_b(bg); + uint16_t b = a8_lerp(fg_b, bg_b, alpha); + + return gfx_color32_rgb(r, g, b); +} + +#else +#error "GFX_COLOR_16BIT/32BIT not specified" +#endif + +// Returns a gradient as an array of 16 consecutive 16-bit colors +// +// Each element in the array represents a color, with `retval[0]` being +// the background (`bg`) color and `retval[15]` the foreground (`fg`) color +const gfx_color16_t* gfx_color16_gradient_a4(gfx_color_t fg, gfx_color_t bg); + +// Returns a gradient as an array of 16 consecutive 32-bit colors +// +// Each element in the array represents a color, with `retval[0]` being +// the background (`bg`) color and `retval[15]` the foreground (`fg`) color +const gfx_color32_t* gfx_color32_gradient_a4(gfx_color_t fg, gfx_color_t bg); + +// Returns a color with alpha channel set +// +// The original color is not modified +static inline gfx_color32_t gfx_color32_set_alpha(gfx_color32_t c, + uint8_t alpha) { + return (c & 0xFFFFFF) | (alpha << 24); +} + +#endif // GFX_COLOR_H diff --git a/core/embed/lib/gfx_draw.c b/core/embed/lib/gfx_draw.c new file mode 100644 index 0000000000..192bfef361 --- /dev/null +++ b/core/embed/lib/gfx_draw.c @@ -0,0 +1,329 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "display_draw.h" +#include "fonts/fonts.h" +#include "gfx_draw.h" + +typedef struct { + int16_t dst_x; + int16_t dst_y; + int16_t src_x; + int16_t src_y; + int16_t width; + int16_t height; +} gfx_clip_t; + +static inline gfx_clip_t gfx_clip(gfx_rect_t dst, const gfx_bitmap_t* bitmap) { + int16_t dst_x = dst.x0; + int16_t dst_y = dst.y0; + + int16_t src_x = 0; + int16_t src_y = 0; + + if (bitmap != NULL) { + src_x += bitmap->offset.x; + src_y += bitmap->offset.y; + + // Normalize negative x-offset of bitmap + if (src_x < 0) { + dst_x -= src_x; + src_x = 0; + } + + // Normalize negative y-offset of src bitmap + if (src_y < 0) { + dst_y -= src_y; + src_y = 0; + } + } + + // Normalize negative top-left of destination rectangle + if (dst_x < 0) { + src_x -= dst_x; + dst_x = 0; + } + + if (dst_y < 0) { + src_y -= dst_y; + dst_y = 0; + } + + // Calculate dimension of effective rectangle + int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x; + int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y; + + if (bitmap != NULL) { + width = MIN(width, bitmap->size.x - src_x); + height = MIN(height, bitmap->size.y - src_y); + } + + gfx_clip_t clip = { + .dst_x = dst_x, + .dst_y = dst_y, + .src_x = src_x, + .src_y = src_y, + .width = width, + .height = height, + }; + + return clip; +} + +void gfx_clear(void) { + gfx_bitblt_t bb = { + // Destination bitmap + .height = DISPLAY_RESY, + .width = DISPLAY_RESX, + .dst_row = NULL, + .dst_x = 0, + .dst_y = 0, + .dst_stride = 0, + + // Source bitmap + .src_fg = 0, + .src_alpha = 255, + }; + + display_fill(&bb); +} + +void gfx_draw_bar(gfx_rect_t rect, gfx_color_t color) { + gfx_clip_t clip = gfx_clip(rect, NULL); + + if (clip.width <= 0 || clip.height <= 0) { + return; + } + + gfx_bitblt_t bb = { + // Destination bitmap + .height = clip.height, + .width = clip.width, + .dst_row = NULL, + .dst_x = clip.dst_x, + .dst_y = clip.dst_y, + .dst_stride = 0, + + // Source bitmap + .src_fg = color, + .src_alpha = 255, + }; + + display_fill(&bb); +} + +void gfx_draw_bitmap(gfx_rect_t rect, const gfx_bitmap_t* bitmap) { + gfx_clip_t clip = gfx_clip(rect, bitmap); + + if (clip.width <= 0 || clip.height <= 0) { + return; + } + + gfx_bitblt_t bb = { + // Destination bitmap + .height = clip.height, + .width = clip.width, + .dst_row = NULL, + .dst_x = clip.dst_x, + .dst_y = clip.dst_y, + .dst_stride = 0, + + // Source bitmap + .src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y, + .src_x = clip.src_x, + .src_y = clip.src_y, + .src_stride = bitmap->stride, + .src_fg = bitmap->fg_color, + .src_bg = bitmap->bg_color, + .src_alpha = 255, + }; + + // Currently, we use `gfx_draw_bitmap` exclusively for text rendering. + // Therefore, we are including the variant of `display_copy_xxx()` that is + // specifically needed for drawing glyphs in the format we are using + // to save some space in the flash memory. + +#if TREZOR_FONT_BPP == 1 + if (bitmap->format == GFX_FORMAT_MONO1P) { + display_copy_mono1p(&bb); + } +#endif +#if TREZOR_FONT_BPP == 4 + if (bitmap->format == GFX_FORMAT_MONO4) { + display_copy_mono4(&bb); + } +#endif +} + +#if TREZOR_FONT_BPP == 1 +#define GLYPH_FORMAT GFX_FORMAT_MONO1P +#define GLYPH_STRIDE(w) (((w) + 7) / 8) +#elif TREZOR_FONT_BPP == 2 +#error Unsupported TREZOR_FONT_BPP value +#define GLYPH_FORMAT GFX_FORMAT_MONO2 +#define GLYPH_STRIDE(w) (((w) + 3) / 4) +#elif TREZOR_FONT_BPP == 4 +#define GLYPH_FORMAT GFX_FORMAT_MONO4 +#define GLYPH_STRIDE(w) (((w) + 1) / 2) +#elif TREZOR_FONT_BPP == 8 +#error Unsupported TREZOR_FONT_BPP value +#define GLYPH_FORMAT GFX_FORMAT_MONO8 +#define GLYPH_STRIDE(w) (w) +#else +#error Unsupported TREZOR_FONT_BPP value +#endif + +#define GLYPH_WIDTH(g) ((g)[0]) +#define GLYPH_HEIGHT(g) ((g)[1]) +#define GLYPH_ADVANCE(g) ((g)[2]) +#define GLYPH_BEARING_X(g) ((g)[3]) +#define GLYPH_BEARING_Y(g) ((g)[4]) +#define GLYPH_DATA(g) ((void*)&(g)[5]) + +void gfx_draw_text(gfx_offset_t pos, const char* text, size_t maxlen, + const gfx_text_attr_t* attr) { + if (text == NULL) { + return; + } + + gfx_bitmap_t bitmap = { + .format = GLYPH_FORMAT, + .fg_color = attr->fg_color, + .bg_color = attr->bg_color, + }; + + int max_height = font_max_height(attr->font); + int baseline = font_baseline(attr->font); + + for (int i = 0; i < maxlen; i++) { + uint8_t ch = (uint8_t)text[i]; + + if (ch == 0 || pos.x >= DISPLAY_RESX) { + break; + } + + const uint8_t* glyph = font_get_glyph(attr->font, ch); + + if (glyph == NULL) { + continue; + } + + bitmap.ptr = GLYPH_DATA(glyph); + bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph)); + bitmap.size.x = GLYPH_WIDTH(glyph); + bitmap.size.y = GLYPH_HEIGHT(glyph); + + bitmap.offset.x = -GLYPH_BEARING_X(glyph); + bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph)); + + gfx_draw_bitmap(gfx_rect(pos.x, pos.y, DISPLAY_RESX, DISPLAY_RESY), + &bitmap); + + pos.x += GLYPH_ADVANCE(glyph); + } +} + +#ifdef TREZOR_PRODTEST + +#include "qr-code-generator/qrcodegen.h" +#define QR_MAX_VERSION 9 + +void gfx_draw_qrcode(int x, int y, uint8_t scale, const char* data) { + if (scale < 1 || scale > 10) return; + + uint8_t codedata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)] = {0}; + uint8_t tempdata[qrcodegen_BUFFER_LEN_FOR_VERSION(QR_MAX_VERSION)] = {0}; + + int side = 0; + if (qrcodegen_encodeText(data, tempdata, codedata, qrcodegen_Ecc_MEDIUM, + qrcodegen_VERSION_MIN, QR_MAX_VERSION, + qrcodegen_Mask_AUTO, true)) { + side = qrcodegen_getSize(codedata); + } + + // Calculate border size (1 extra modules around the QR code) + int border_side = ((side + 2) * scale); + + // Calculate border left-top corner + x -= border_side / 2; + y -= border_side / 2; + + // Fill the backround (including the border) with white color + gfx_rect_t border_rect = gfx_rect_wh(x, y, border_side, border_side); + gfx_draw_bar(border_rect, COLOR_WHITE); + + // Center QR code inside the border + x += scale; + y += scale; + + // Draw black modules + for (int i = 0; i < side; i++) { + for (int j = 0; j < side; j++) { + if (qrcodegen_getModule(codedata, i, j)) { + gfx_rect_t rect = + gfx_rect_wh(x + i * scale, y + j * scale, scale, scale); + gfx_draw_bar(rect, COLOR_BLACK); + } + } + } +} + +#endif // TREZOR_PRODTEST + +// =============================================================== +// emulation of legacy functions + +void display_clear(void) { gfx_clear(); } + +void display_bar(int x, int y, int w, int h, uint16_t c) { + gfx_draw_bar(gfx_rect_wh(x, y, w, h), c); +} + +void display_text(int x, int y, const char* text, int textlen, int font, + uint16_t fg_color, uint16_t bg_color) { + gfx_text_attr_t attr = { + .font = font, + .fg_color = fg_color, + .bg_color = bg_color, + }; + + size_t maxlen = textlen < 0 ? UINT32_MAX : textlen; + gfx_draw_text(gfx_offset(x, y), text, maxlen, &attr); +} + +void display_text_center(int x, int y, const char* text, int textlen, int font, + uint16_t fg_color, uint16_t bg_color) { + gfx_text_attr_t attr = { + .font = font, + .fg_color = fg_color, + .bg_color = bg_color, + }; + + size_t maxlen = textlen < 0 ? UINT32_MAX : textlen; + int w = font_text_width(font, text, textlen); + gfx_draw_text(gfx_offset(x - w / 2, y), text, maxlen, &attr); +} + +#ifdef TREZOR_PRODTEST +void display_qrcode(int x, int y, const char* data, uint8_t scale) { + gfx_draw_qrcode(x, y, scale, data); +} +#endif // TREZOR_PRODTEST diff --git a/core/embed/lib/gfx_draw.h b/core/embed/lib/gfx_draw.h new file mode 100644 index 0000000000..280c13abdb --- /dev/null +++ b/core/embed/lib/gfx_draw.h @@ -0,0 +1,162 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef GFX_DRAW_H +#define GFX_DRAW_H + +#include "gfx_color.h" + +// 2D rectangle coordinates +// +// `x0`, `y0` - top-left coordinates +// `x1`, `y1` - bottom-right coordinates point (not included) +typedef struct { + int16_t x0; + int16_t y0; + int16_t x1; + int16_t y1; +} gfx_rect_t; + +// Builds a rectangle (`gfx_rect_t`) from top-left coordinates and dimensions +static inline gfx_rect_t gfx_rect_wh(int16_t x, int16_t y, int16_t w, + int16_t h) { + gfx_rect_t rect = { + .x0 = x, + .y0 = y, + .x1 = x + w, + .y1 = y + h, + }; + + return rect; +} + +// Builds a rectangle (`gfx_rect_t`) from top-left and bottom-right coordinates +static inline gfx_rect_t gfx_rect(int16_t x0, int16_t y0, int16_t x1, + int16_t y1) { + gfx_rect_t rect = { + .x0 = x0, + .y0 = y0, + .x1 = x1, + .y1 = y1, + }; + + return rect; +} + +// 2D offset/ coordinates +typedef struct { + int16_t x; + int16_t y; +} gfx_offset_t; + +// Builds a `gfx_offset_t` structure +static inline gfx_offset_t gfx_offset(int16_t x, int16_t y) { + gfx_offset_t offset = { + .x = x, + .y = y, + }; + + return offset; +} + +// 2D size in pixels +typedef struct { + int16_t x; + int16_t y; +} gfx_size_t; + +// Builds a `gfx_size_t` structure +static inline gfx_size_t gfx_size(int16_t x, int16_t y) { + gfx_size_t size = { + .x = x, + .y = y, + }; + + return size; +} + +// Format of pixels in a bitmap +typedef enum { + GFX_FORMAT_UNKNOWN, // + GFX_FORMAT_MONO1P, // 1-bpp per pixel (packed) + GFX_FORMAT_MONO4, // 4-bpp per pixel + GFX_FORMAT_RGB565, // 16-bpp per pixel + GFX_FORMAT_RGBA8888, // 32-bpp +} gfx_format_t; + +// 2D bitmap reference +typedef struct { + // pointer to top-left pixel + void* ptr; + // stride in bytes + size_t stride; + // size in pixels + gfx_size_t size; + // format of pixels, GFX_FORMAT_xxx + uint8_t format; + // offset used when bitmap is drawed using gfx_draw_bitmap() + gfx_offset_t offset; + // foreground color (used with MONOx formats) + gfx_color_t fg_color; + // background color (used with MONOx formats) + gfx_color_t bg_color; +} gfx_bitmap_t; + +// Text attributes (font and color) +typedef struct { + // Font identifier + int font; + // Foreground color + gfx_color_t fg_color; + // Background color + gfx_color_t bg_color; +} gfx_text_attr_t; + +// Fills a rectangle with a specified color. +void gfx_draw_bar(gfx_rect_t rect, gfx_color_t color); + +// Draws a bitmap into the specified rectangle. +// +// The destination rectangle may not be fully filled if the source bitmap +// is smaller than destination rectangle or if the bitmap is translated by +// an offset partially or completely outside the destination rectangle. +// +// Currently, we use `gfx_draw_bitmap` exclusively for text rendering. +// Not all bitmap formats are supported now. Please see the implementation. +void gfx_draw_bitmap(gfx_rect_t rect, const gfx_bitmap_t* bitmap); + +// Draws a text to the specified position. +// +// `offset` - the most left point on the font baseline +// `text` - utf-8 text +// `maxlen` - maximum number of characters displayed (use SIZE_MAX when not +// specified) `attr` - font & text color +void gfx_draw_text(gfx_offset_t offset, const char* text, size_t maxlen, + const gfx_text_attr_t* attr); + +#ifdef TREZOR_PRODTEST +// Draws a QR code to the specified position. +// +// `x`, `y` - center of the QR code +// `scale` - size of a single QR code module +// `data` - utf-8 text +void gfx_draw_qrcode(int x, int y, uint8_t scale, const char* data); +#endif + +#endif // GFX_DRAW_H diff --git a/core/embed/lib/image.c b/core/embed/lib/image.c index c2eaad3ab8..0dc6a6f22a 100644 --- a/core/embed/lib/image.c +++ b/core/embed/lib/image.c @@ -26,6 +26,8 @@ #include "image.h" #include "model.h" +_Static_assert(VENDOR_HEADER_MAX_SIZE + IMAGE_HEADER_SIZE <= IMAGE_CHUNK_SIZE); + const uint8_t BOOTLOADER_KEY_M = 2; const uint8_t BOOTLOADER_KEY_N = 3; static const uint8_t * const BOOTLOADER_KEYS[] = { @@ -150,7 +152,7 @@ secbool __wur read_vendor_header(const uint8_t *const data, if (vhdr->magic != 0x565A5254) return secfalse; // TRZV memcpy(&vhdr->hdrlen, data + 4, 4); - if (vhdr->hdrlen > 64 * 1024) return secfalse; + if (vhdr->hdrlen > VENDOR_HEADER_MAX_SIZE) return secfalse; memcpy(&vhdr->expiry, data + 8, 4); if (vhdr->expiry != 0) return secfalse; @@ -162,6 +164,7 @@ secbool __wur read_vendor_header(const uint8_t *const data, memcpy(&vhdr->vsig_m, data + 14, 1); memcpy(&vhdr->vsig_n, data + 15, 1); memcpy(&vhdr->vtrust, data + 16, 2); + memcpy(&vhdr->hw_model, data + 18, 4); if (vhdr->vsig_n > MAX_VENDOR_PUBLIC_KEYS) { return secfalse; @@ -190,6 +193,20 @@ secbool __wur read_vendor_header(const uint8_t *const data, return sectrue; } +secbool check_vendor_header_model(const vendor_header *const vhdr) { +#ifdef TREZOR_MODEL_T + if (vhdr->hw_model == 0) { + // vendor headers for model T have this field set to 0 + return sectrue; + } +#endif + if (vhdr->hw_model == HW_MODEL) { + return sectrue; + } + + return secfalse; +} + secbool check_vendor_header_sig(const vendor_header *const vhdr, uint8_t key_m, uint8_t key_n, const uint8_t *const *keys) { if (vhdr == NULL) { @@ -245,9 +262,19 @@ secbool check_image_contents(const image_header *const hdr, uint32_t firstskip, } // Check the firmware integrity, calculate and compare hashes - size_t offset = firstskip; + size_t offset = IMAGE_CODE_ALIGN(firstskip); size_t end_offset = offset + hdr->codelen; + // Check area between headers and code + uint32_t padding_size = offset - firstskip; + const uint8_t *addr = + (uint8_t *)flash_area_get_address(area, firstskip, padding_size); + for (size_t i = 0; i < padding_size; i++) { + if (*addr++ != 0) { + return secfalse; + } + } + while (offset < end_offset) { size_t bytes_to_check = MIN(IMAGE_CHUNK_SIZE - (offset % IMAGE_CHUNK_SIZE), end_offset - offset); diff --git a/core/embed/lib/image.h b/core/embed/lib/image.h index bd4fc3508b..bfcfba634b 100644 --- a/core/embed/lib/image.h +++ b/core/embed/lib/image.h @@ -27,6 +27,7 @@ #include "model.h" #include "secbool.h" +#define VENDOR_HEADER_MAX_SIZE (64 * 1024) #define IMAGE_HEADER_SIZE 0x400 // size of the bootloader or firmware header #define IMAGE_SIG_SIZE 65 #define IMAGE_INIT_CHUNK_SIZE (16 * 1024) @@ -35,6 +36,9 @@ #define FIRMWARE_IMAGE_MAGIC 0x465A5254 // TRZF +#define IMAGE_CODE_ALIGN(addr) \ + ((((uint32_t)(uintptr_t)addr) + (CODE_ALIGNMENT - 1)) & ~(CODE_ALIGNMENT - 1)) + typedef struct { uint32_t magic; uint32_t hdrlen; @@ -54,19 +58,28 @@ typedef struct { #define MAX_VENDOR_PUBLIC_KEYS 8 -#define VTRUST_WAIT 0x000F -#define VTRUST_RED 0x0010 -#define VTRUST_CLICK 0x0020 -#define VTRUST_STRING 0x0040 +// The mask of the vendor screen wait time in seconds, encoded in bitwise +// complement form. +#define VTRUST_WAIT_MASK 0x000F + +// Use black background instead of red one in the vendor screen. +#define VTRUST_NO_RED 0x0010 + +// Do not require user click to leave the vendor screen. +#define VTRUST_NO_CLICK 0x0020 + +// Do not show vendor string in the vendor screen. +#define VTRUST_NO_STRING 0x0040 // Two bits for historical reasons. On T2B1, only the lower bit was used with // inverted logic (due to late inclusion of the secret handling during // development process). On T3T1, we decided to remedy the situation by // including the upper bit as well. -#define VTRUST_SECRET 0x0180 +#define VTRUST_SECRET_MASK 0x0180 #define VTRUST_SECRET_ALLOW 0x0100 -#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING) +#define VTRUST_NO_WARNING \ + (VTRUST_WAIT_MASK | VTRUST_NO_RED | VTRUST_NO_CLICK | VTRUST_NO_STRING) typedef struct { uint32_t magic; @@ -76,7 +89,8 @@ typedef struct { uint8_t vsig_m; uint8_t vsig_n; uint16_t vtrust; - // uint8_t reserved[14]; + uint32_t hw_model; + // uint8_t reserved[10]; const uint8_t *vpub[MAX_VENDOR_PUBLIC_KEYS]; uint8_t vstr_len; const char *vstr; @@ -115,6 +129,8 @@ secbool __wur check_image_header_sig(const image_header *const hdr, secbool __wur read_vendor_header(const uint8_t *const data, vendor_header *const vhdr); +secbool __wur check_vendor_header_model(const vendor_header *const vhdr); + secbool __wur check_vendor_header_sig(const vendor_header *const vhdr, uint8_t key_m, uint8_t key_n, const uint8_t *const *keys); diff --git a/core/embed/lib/terminal.c b/core/embed/lib/terminal.c index 9411cbdff9..0891fcbedf 100644 --- a/core/embed/lib/terminal.c +++ b/core/embed/lib/terminal.c @@ -24,7 +24,8 @@ #include "display.h" #include TREZOR_BOARD -#ifndef TREZOR_PRINT_DISABLE +#include "fonts/fonts.h" +#include "gfx_draw.h" #define TERMINAL_COLS (DISPLAY_RESX / 6) #define TERMINAL_ROWS (DISPLAY_RESY / 8) @@ -39,6 +40,62 @@ void term_set_color(uint16_t fgcolor, uint16_t bgcolor) { terminal_bgcolor = bgcolor; } +#ifdef NEW_RENDERING + +// Font_Bitmap contains 96 (0x20 - 0x7F) 5x7 glyphs +// Each glyph consists of 5 bytes (each byte represents one column) +// +// This function converts the glyph into the format compatible +// with `display_copy_mono1p()` functions. +static uint64_t term_glyph_bits(char ch) { + union { + uint64_t u64; + uint8_t bytes[8]; + } result = {0}; + + if (ch > 32 && (uint8_t)ch < 128) { + const uint8_t *b = &Font_Bitmap[(ch - ' ') * 5]; + + for (int y = 0; y < 7; y++) { + uint8_t mask = 1 << y; + result.bytes[y] |= ((b[0] & mask) ? 128 : 0) + ((b[1] & mask) ? 64 : 0) + + ((b[2] & mask) ? 32 : 0) + ((b[3] & mask) ? 16 : 0) + + ((b[4] & mask) ? 8 : 0); + } + } + return result.u64; +} + +// Redraws specified rows to the display +static void term_redraw_rows(int start_row, int row_count) { + uint64_t glyph_bits = 0; + gfx_bitblt_t bb = { + .height = 8, + .width = 6, + .dst_row = NULL, + .dst_x = 0, + .dst_y = 0, + .dst_stride = 0, + + .src_row = &glyph_bits, + .src_x = 0, + .src_y = 0, + .src_stride = 8, + .src_fg = terminal_fgcolor, + .src_bg = terminal_bgcolor, + }; + + for (int y = start_row; y < start_row + row_count; y++) { + bb.dst_y = y * 8; + for (int x = 0; x < TERMINAL_COLS; x++) { + glyph_bits = term_glyph_bits(terminal_fb[y][x]); + bb.dst_x = x * 6; + display_copy_mono1p(&bb); + } + } +} +#endif // NEW_RENDERING + // display text using bitmap font void term_print(const char *text, int textlen) { static uint8_t row = 0, col = 0; @@ -77,6 +134,10 @@ void term_print(const char *text, int textlen) { } } +#ifdef NEW_RENDERING + term_redraw_rows(0, TERMINAL_ROWS); + display_refresh(); +#else // NEW RENDERING // render buffer to display display_set_window(0, 0, DISPLAY_RESX - 1, DISPLAY_RESY - 1); for (int i = 0; i < DISPLAY_RESX * DISPLAY_RESY; i++) { @@ -105,6 +166,7 @@ void term_print(const char *text, int textlen) { } display_pixeldata_dirty(); display_refresh(); +#endif } #ifdef TREZOR_EMULATOR @@ -118,14 +180,18 @@ void term_print(const char *text, int textlen) { void term_printf(const char *fmt, ...) { if (!strchr(fmt, '%')) { term_print(fmt, strlen(fmt)); +#ifdef TREZOR_EMULATOR + printf("%s", fmt); +#endif } else { va_list va; va_start(va, fmt); char buf[256] = {0}; int len = mini_vsnprintf(buf, sizeof(buf), fmt, va); term_print(buf, len); +#ifdef TREZOR_EMULATOR + vprintf(fmt, va); +#endif va_end(va); } } - -#endif // TREZOR_PRINT_DISABLE diff --git a/core/embed/lib/terminal.h b/core/embed/lib/terminal.h index 7cc036dffb..d1dc9bfa01 100644 --- a/core/embed/lib/terminal.h +++ b/core/embed/lib/terminal.h @@ -22,11 +22,9 @@ #include "colors.h" -#ifndef TREZOR_PRINT_DISABLE void term_set_color(uint16_t fgcolor, uint16_t bgcolor); void term_print(const char *text, int textlen); void term_printf(const char *fmt, ...) __attribute__((__format__(__printf__, 1, 2))); -#endif #endif // LIB_TERMINAL_H diff --git a/core/embed/lib/touch.c b/core/embed/lib/touch.c deleted file mode 100644 index 197d209f67..0000000000 --- a/core/embed/lib/touch.c +++ /dev/null @@ -1,22 +0,0 @@ - -#ifdef USE_TOUCH -#include "touch.h" - -uint32_t touch_click(void) { - uint32_t r = 0; - // flush touch events if any - while (touch_read()) { - } - // wait for TOUCH_START - while ((touch_read() & TOUCH_START) == 0) { - } - // wait for TOUCH_END - while (((r = touch_read()) & TOUCH_END) == 0) { - } - // flush touch events if any - while (touch_read()) { - } - // return last touch coordinate - return r; -} -#endif diff --git a/core/embed/trezorhal/boards/stm32f429i-disc1.h b/core/embed/models/D001/boards/stm32f429i-disc1.h similarity index 89% rename from core/embed/trezorhal/boards/stm32f429i-disc1.h rename to core/embed/models/D001/boards/stm32f429i-disc1.h index 9f8b0a65ec..cd37a97124 100644 --- a/core/embed/trezorhal/boards/stm32f429i-disc1.h +++ b/core/embed/models/D001/boards/stm32f429i-disc1.h @@ -3,18 +3,16 @@ #define HSE_8MHZ -#define MAX_DISPLAY_RESX 240 -#define MAX_DISPLAY_RESY 320 #define DISPLAY_RESX 240 #define DISPLAY_RESY 320 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 +#define DISPLAY_LEGACY_HEADER "displays/ltdc.h" #define USE_I2C 1 #define USE_TOUCH 1 #define USE_SDRAM 1 #define USE_RGB_COLORS 1 -#include "displays/ltdc.h" - #define I2C_COUNT 1 #define I2C_INSTANCE_0 I2C3 #define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C3_CLK_ENABLE diff --git a/core/embed/models/model_D001.h b/core/embed/models/D001/model_D001.h similarity index 95% rename from core/embed/models/model_D001.h rename to core/embed/models/D001/model_D001.h index 9f54bad1a7..c0ed207687 100644 --- a/core/embed/models/model_D001.h +++ b/core/embed/models/D001/model_D001.h @@ -6,6 +6,8 @@ #define MODEL_INTERNAL_NAME "D001" #define MODEL_INTERNAL_NAME_TOKEN T #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_D001 +#define MODEL_USB_MANUFACTURER "Trezor DIY" +#define MODEL_USB_PRODUCT MODEL_FULL_NAME /*** Discovery uses DEV keys in any build variant ***/ #define MODEL_BOARDLOADER_KEYS \ @@ -21,6 +23,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/D001/model_D001_layout.c b/core/embed/models/D001/model_D001_layout.c new file mode 120000 index 0000000000..6851dc987b --- /dev/null +++ b/core/embed/models/D001/model_D001_layout.c @@ -0,0 +1 @@ +../T2T1/model_T2T1_layout.c \ No newline at end of file diff --git a/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/D001/vendorheader/vendor_dev_DO_NOT_SIGN.json similarity index 100% rename from core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.json rename to core/embed/models/D001/vendorheader/vendor_dev_DO_NOT_SIGN.json diff --git a/core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/D001/vendorheader/vendor_dev_DO_NOT_SIGN.toif similarity index 100% rename from core/embed/vendorheader/D001/vendor_dev_DO_NOT_SIGN.toif rename to core/embed/models/D001/vendorheader/vendor_dev_DO_NOT_SIGN.toif diff --git a/core/embed/vendorheader/D001/vendor_unsafe.json b/core/embed/models/D001/vendorheader/vendor_unsafe.json similarity index 100% rename from core/embed/vendorheader/D001/vendor_unsafe.json rename to core/embed/models/D001/vendorheader/vendor_unsafe.json diff --git a/core/embed/vendorheader/D001/vendor_unsafe.toif b/core/embed/models/D001/vendorheader/vendor_unsafe.toif similarity index 100% rename from core/embed/vendorheader/D001/vendor_unsafe.toif rename to core/embed/models/D001/vendorheader/vendor_unsafe.toif diff --git a/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/D001/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin rename to core/embed/models/D001/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin diff --git a/core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/D001/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 100% rename from core/embed/vendorheader/D001/vendorheader_dev_DO_NOT_SIGN_unsigned.bin rename to core/embed/models/D001/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin diff --git a/core/embed/vendorheader/D001/vendorheader_unsafe_signed_dev.bin b/core/embed/models/D001/vendorheader/vendorheader_unsafe_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/D001/vendorheader_unsafe_signed_dev.bin rename to core/embed/models/D001/vendorheader/vendorheader_unsafe_signed_dev.bin diff --git a/core/embed/vendorheader/D001/vendorheader_unsafe_signed_prod.bin b/core/embed/models/D001/vendorheader/vendorheader_unsafe_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/D001/vendorheader_unsafe_signed_prod.bin rename to core/embed/models/D001/vendorheader/vendorheader_unsafe_signed_prod.bin diff --git a/core/embed/vendorheader/D001/vendorheader_unsafe_unsigned.bin b/core/embed/models/D001/vendorheader/vendorheader_unsafe_unsigned.bin similarity index 100% rename from core/embed/vendorheader/D001/vendorheader_unsafe_unsigned.bin rename to core/embed/models/D001/vendorheader/vendorheader_unsafe_unsigned.bin diff --git a/core/embed/models/D001/versions.h b/core/embed/models/D001/versions.h new file mode 100644 index 0000000000..42408b3df8 --- /dev/null +++ b/core/embed/models/D001/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 1 +#define FIRMWARE_MONOTONIC_VERSION 1 diff --git a/core/embed/trezorhal/boards/stm32u5a9j-dk.h b/core/embed/models/D002/boards/stm32u5a9j-dk.h similarity index 80% rename from core/embed/trezorhal/boards/stm32u5a9j-dk.h rename to core/embed/models/D002/boards/stm32u5a9j-dk.h index 3ff3673ee6..baf3e71171 100644 --- a/core/embed/trezorhal/boards/stm32u5a9j-dk.h +++ b/core/embed/models/D002/boards/stm32u5a9j-dk.h @@ -7,11 +7,15 @@ #define USE_I2C 1 #define USE_RGB_COLORS 1 #define USE_TOUCH 1 -//#define USE_SBU 1 -//#define USE_DISP_I8080_8BIT_DW 1 +// #define USE_SBU 1 +// #define USE_DISP_I8080_8BIT_DW 1 #define USE_HASH_PROCESSOR 1 -#include "displays/dsi.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 + +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_ARGB8888 +#define DISPLAY_LEGACY_HEADER "displays/dsi.h" #define I2C_COUNT 1 #define I2C_INSTANCE_0 I2C5 diff --git a/core/embed/models/model_D002.h b/core/embed/models/D002/model_D002.h similarity index 95% rename from core/embed/models/model_D002.h rename to core/embed/models/D002/model_D002.h index 3c6d8d6a85..217974ca69 100644 --- a/core/embed/models/model_D002.h +++ b/core/embed/models/D002/model_D002.h @@ -9,6 +9,8 @@ #define MODEL_INTERNAL_NAME_TOKEN D002 #define MODEL_NAME_QSTR MP_QSTR_T #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_D001 +#define MODEL_USB_MANUFACTURER "Trezor DIY" +#define MODEL_USB_PRODUCT MODEL_FULL_NAME /*** Discovery uses DEV keys in any build variant ***/ #define MODEL_BOARDLOADER_KEYS \ @@ -24,6 +26,7 @@ #define IMAGE_CHUNK_SIZE SIZE_256K #define IMAGE_HASH_SHA256 #define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x400 // SHARED WITH MAKEFILE #define FLASH_START 0x0C000000 diff --git a/core/embed/models/model_D002_layout.c b/core/embed/models/D002/model_D002_layout.c similarity index 100% rename from core/embed/models/model_D002_layout.c rename to core/embed/models/D002/model_D002_layout.c diff --git a/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/D002/vendorheader/vendor_dev_DO_NOT_SIGN.json similarity index 100% rename from core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.json rename to core/embed/models/D002/vendorheader/vendor_dev_DO_NOT_SIGN.json diff --git a/core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/D002/vendorheader/vendor_dev_DO_NOT_SIGN.toif similarity index 100% rename from core/embed/vendorheader/D002/vendor_dev_DO_NOT_SIGN.toif rename to core/embed/models/D002/vendorheader/vendor_dev_DO_NOT_SIGN.toif diff --git a/core/embed/vendorheader/D002/vendor_unsafe.json b/core/embed/models/D002/vendorheader/vendor_unsafe.json similarity index 100% rename from core/embed/vendorheader/D002/vendor_unsafe.json rename to core/embed/models/D002/vendorheader/vendor_unsafe.json diff --git a/core/embed/vendorheader/D002/vendor_unsafe.toif b/core/embed/models/D002/vendorheader/vendor_unsafe.toif similarity index 100% rename from core/embed/vendorheader/D002/vendor_unsafe.toif rename to core/embed/models/D002/vendorheader/vendor_unsafe.toif diff --git a/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/D002/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin rename to core/embed/models/D002/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin diff --git a/core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/D002/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 100% rename from core/embed/vendorheader/D002/vendorheader_dev_DO_NOT_SIGN_unsigned.bin rename to core/embed/models/D002/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin diff --git a/core/embed/vendorheader/D002/vendorheader_unsafe_signed_dev.bin b/core/embed/models/D002/vendorheader/vendorheader_unsafe_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/D002/vendorheader_unsafe_signed_dev.bin rename to core/embed/models/D002/vendorheader/vendorheader_unsafe_signed_dev.bin diff --git a/core/embed/vendorheader/D002/vendorheader_unsafe_unsigned.bin b/core/embed/models/D002/vendorheader/vendorheader_unsafe_unsigned.bin similarity index 100% rename from core/embed/vendorheader/D002/vendorheader_unsafe_unsigned.bin rename to core/embed/models/D002/vendorheader/vendorheader_unsafe_unsigned.bin diff --git a/core/embed/models/D002/versions.h b/core/embed/models/D002/versions.h new file mode 100644 index 0000000000..42408b3df8 --- /dev/null +++ b/core/embed/models/D002/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 1 +#define FIRMWARE_MONOTONIC_VERSION 1 diff --git a/core/embed/trezorhal/unix/background_1.h b/core/embed/models/T1B1/background_1.h similarity index 100% rename from core/embed/trezorhal/unix/background_1.h rename to core/embed/models/T1B1/background_1.h diff --git a/core/embed/trezorhal/unix/background_1.jpg b/core/embed/models/T1B1/background_1.jpg similarity index 100% rename from core/embed/trezorhal/unix/background_1.jpg rename to core/embed/models/T1B1/background_1.jpg diff --git a/core/embed/models/T1B1/boards/t1b1-unix.h b/core/embed/models/T1B1/boards/t1b1-unix.h new file mode 100644 index 0000000000..5570a6e96b --- /dev/null +++ b/core/embed/models/T1B1/boards/t1b1-unix.h @@ -0,0 +1,22 @@ +#ifndef BOARDS_T1B1_UNIX_H +#define BOARDS_T1B1_UNIX_H + +#define USE_BUTTON 1 + +#define MAX_DISPLAY_RESX 128 +#define MAX_DISPLAY_RESY 64 +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define TREZOR_FONT_BPP 1 + +#define WINDOW_WIDTH 200 +#define WINDOW_HEIGHT 340 +#define TOUCH_OFFSET_X 36 +#define TOUCH_OFFSET_Y 92 + +#define ORIENTATION_NS 1 + +#define BACKGROUND_FILE "T1B1/background_1.h" +#define BACKGROUND_NAME background_1_jpg + +#endif // BOARDS_T1B1_UNIX_H diff --git a/core/embed/trezorhal/boards/trezor_1.h b/core/embed/models/T1B1/boards/trezor_1.h similarity index 95% rename from core/embed/trezorhal/boards/trezor_1.h rename to core/embed/models/T1B1/boards/trezor_1.h index 4f126a7206..7fec05ac7b 100644 --- a/core/embed/trezorhal/boards/trezor_1.h +++ b/core/embed/models/T1B1/boards/trezor_1.h @@ -5,7 +5,8 @@ #define USE_BUTTON 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 #define BTN_LEFT_PIN GPIO_PIN_5 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/models/model_T1B1.h b/core/embed/models/T1B1/model_T1B1.h similarity index 88% rename from core/embed/models/model_T1B1.h rename to core/embed/models/T1B1/model_T1B1.h index c29414ea68..e5006b01e4 100644 --- a/core/embed/models/model_T1B1.h +++ b/core/embed/models/T1B1/model_T1B1.h @@ -6,9 +6,12 @@ #define MODEL_INTERNAL_NAME "T1B1" #define MODEL_INTERNAL_NAME_TOKEN T1B1 #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T1B1 +#define MODEL_USB_MANUFACTURER "SatoshiLabs" +#define MODEL_USB_PRODUCT "TREZOR" #define IMAGE_CHUNK_SIZE (64 * 1024) #define IMAGE_HASH_SHA256 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/model_T1B1_layout.c b/core/embed/models/T1B1/model_T1B1_layout.c similarity index 100% rename from core/embed/models/model_T1B1_layout.c rename to core/embed/models/T1B1/model_T1B1_layout.c diff --git a/core/embed/models/T1B1/versions.h b/core/embed/models/T1B1/versions.h new file mode 100644 index 0000000000..42408b3df8 --- /dev/null +++ b/core/embed/models/T1B1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 1 +#define FIRMWARE_MONOTONIC_VERSION 1 diff --git a/core/embed/trezorhal/unix/background_T2B1.h b/core/embed/models/T2B1/background_T2B1.h similarity index 100% rename from core/embed/trezorhal/unix/background_T2B1.h rename to core/embed/models/T2B1/background_T2B1.h diff --git a/core/embed/trezorhal/unix/background_T2B1.png b/core/embed/models/T2B1/background_T2B1.png similarity index 100% rename from core/embed/trezorhal/unix/background_T2B1.png rename to core/embed/models/T2B1/background_T2B1.png diff --git a/core/embed/models/T2B1/boards/t2b1-unix.h b/core/embed/models/T2B1/boards/t2b1-unix.h new file mode 100644 index 0000000000..c1ae569781 --- /dev/null +++ b/core/embed/models/T2B1/boards/t2b1-unix.h @@ -0,0 +1,24 @@ +#ifndef BOARDS_T2B1_UNIX_H +#define BOARDS_T2B1_UNIX_H + +#define USE_BUTTON 1 +#define USE_SBU 1 +#define USE_OPTIGA 1 + +#define MAX_DISPLAY_RESX 128 +#define MAX_DISPLAY_RESY 64 +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define TREZOR_FONT_BPP 1 + +#define WINDOW_WIDTH 193 +#define WINDOW_HEIGHT 339 +#define TOUCH_OFFSET_X 32 +#define TOUCH_OFFSET_Y 84 + +#define ORIENTATION_NS 1 + +#define BACKGROUND_FILE "T2B1/background_T2B1.h" +#define BACKGROUND_NAME background_T2B1_png + +#endif // BOARDS_T2B1_UNIX_H diff --git a/core/embed/trezorhal/boards/trezor_r_v10.h b/core/embed/models/T2B1/boards/trezor_r_v10.h similarity index 94% rename from core/embed/trezorhal/boards/trezor_r_v10.h rename to core/embed/models/T2B1/boards/trezor_r_v10.h index be44e5585d..b48479d526 100644 --- a/core/embed/trezorhal/boards/trezor_r_v10.h +++ b/core/embed/models/T2B1/boards/trezor_r_v10.h @@ -8,7 +8,9 @@ #define USE_I2C 1 #define USE_CONSUMPTION_MASK 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_10 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_r_v3.h b/core/embed/models/T2B1/boards/trezor_r_v3.h similarity index 76% rename from core/embed/trezorhal/boards/trezor_r_v3.h rename to core/embed/models/T2B1/boards/trezor_r_v3.h index 242a3f5416..ffe8b69148 100644 --- a/core/embed/trezorhal/boards/trezor_r_v3.h +++ b/core/embed/models/T2B1/boards/trezor_r_v3.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/ug-2828tswig01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 128 +#define DISPLAY_LEGACY_HEADER "displays/ug-2828tswig01.h" #define BTN_LEFT_PIN GPIO_PIN_0 #define BTN_LEFT_PORT GPIOA diff --git a/core/embed/trezorhal/boards/trezor_r_v4.h b/core/embed/models/T2B1/boards/trezor_r_v4.h similarity index 91% rename from core/embed/trezorhal/boards/trezor_r_v4.h rename to core/embed/models/T2B1/boards/trezor_r_v4.h index 29054d200b..9dbbb62671 100644 --- a/core/embed/trezorhal/boards/trezor_r_v4.h +++ b/core/embed/models/T2B1/boards/trezor_r_v4.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_5 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_r_v6.h b/core/embed/models/T2B1/boards/trezor_r_v6.h similarity index 91% rename from core/embed/trezorhal/boards/trezor_r_v6.h rename to core/embed/models/T2B1/boards/trezor_r_v6.h index 72a7cedeaa..d177c3d726 100644 --- a/core/embed/trezorhal/boards/trezor_r_v6.h +++ b/core/embed/models/T2B1/boards/trezor_r_v6.h @@ -6,7 +6,9 @@ #define USE_BUTTON 1 #define USE_SBU 1 -#include "displays/vg-2864ksweg01.h" +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" #define BTN_LEFT_PIN GPIO_PIN_10 #define BTN_LEFT_PORT GPIOC diff --git a/core/embed/firmware/bootloaders/bootloader_T2B1.bin b/core/embed/models/T2B1/bootloaders/bootloader_T2B1.bin similarity index 100% rename from core/embed/firmware/bootloaders/bootloader_T2B1.bin rename to core/embed/models/T2B1/bootloaders/bootloader_T2B1.bin diff --git a/core/embed/firmware/bootloaders/bootloader_T2B1_qa.bin b/core/embed/models/T2B1/bootloaders/bootloader_T2B1_qa.bin similarity index 100% rename from core/embed/firmware/bootloaders/bootloader_T2B1_qa.bin rename to core/embed/models/T2B1/bootloaders/bootloader_T2B1_qa.bin diff --git a/core/embed/models/T2B1/bootloaders/bootloader_hashes.h b/core/embed/models/T2B1/bootloaders/bootloader_hashes.h new file mode 100644 index 0000000000..2e65297edc --- /dev/null +++ b/core/embed/models/T2B1/bootloaders/bootloader_hashes.h @@ -0,0 +1,17 @@ +#ifndef BOOTLOADER_HASHES_H +#define BOOTLOADER_HASHES_H + +// Auto-generated file, do not edit. + +// clang-format off +// bootloader_T2B1.bin version 2.1.4.0 +#define BOOTLOADER_T2B1_00 {0x12, 0xf5, 0x51, 0x01, 0x10, 0xb3, 0x59, 0x8e, 0x73, 0x95, 0xa9, 0xa8, 0xc5, 0xbc, 0x3a, 0x53, 0xa3, 0xa8, 0xed, 0x83, 0x32, 0xc2, 0xd2, 0x5b, 0x47, 0x99, 0x27, 0x9f, 0x93, 0x8b, 0xb3, 0xd6} +#define BOOTLOADER_T2B1_FF {0x19, 0x7c, 0x2a, 0xd1, 0xba, 0x89, 0xeb, 0x2a, 0xfc, 0xe1, 0x7b, 0xf3, 0x62, 0x7d, 0xf8, 0xb2, 0x3c, 0x70, 0x16, 0x03, 0x53, 0xad, 0x8e, 0x90, 0x9b, 0x57, 0xeb, 0x4b, 0x83, 0x4d, 0xa0, 0x34} + +// bootloader_T2B1_qa.bin version 2.1.4.0 +#define BOOTLOADER_T2B1_QA_00 {0x96, 0xe7, 0xfa, 0x21, 0x66, 0x81, 0x6b, 0x27, 0xf6, 0x27, 0xc1, 0x50, 0xaa, 0xf8, 0xbf, 0xac, 0xf5, 0x0d, 0x37, 0xea, 0x10, 0xa9, 0xa2, 0x0c, 0x1a, 0x58, 0xa7, 0x42, 0x23, 0x80, 0xbe, 0x40} +#define BOOTLOADER_T2B1_QA_FF {0x7c, 0xca, 0xde, 0xf6, 0x8f, 0xf8, 0x9a, 0x08, 0x35, 0x0a, 0x82, 0xe4, 0xb5, 0x76, 0x37, 0x36, 0x51, 0x33, 0x40, 0xd9, 0x66, 0x84, 0xfb, 0x1b, 0x4f, 0x89, 0x34, 0xcd, 0x6f, 0x4c, 0x03, 0x1a} + +// clang-format on + +#endif diff --git a/core/embed/models/model_T2B1.h b/core/embed/models/T2B1/model_T2B1.h similarity index 93% rename from core/embed/models/model_T2B1.h rename to core/embed/models/T2B1/model_T2B1.h index 12774b757b..d82aefc89b 100644 --- a/core/embed/models/model_T2B1.h +++ b/core/embed/models/T2B1/model_T2B1.h @@ -1,11 +1,15 @@ #ifndef MODELS_MODEL_T2B1_H_ #define MODELS_MODEL_T2B1_H_ +#include "bootloaders/bootloader_hashes.h" + #define MODEL_NAME "Safe 3" #define MODEL_FULL_NAME "Trezor Safe 3" #define MODEL_INTERNAL_NAME "T2B1" #define MODEL_INTERNAL_NAME_TOKEN T2B1 #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T2B1 +#define MODEL_USB_MANUFACTURER "SatoshiLabs" +#define MODEL_USB_PRODUCT "TREZOR" /*** PRODUCTION KEYS ***/ #define MODEL_BOARDLOADER_KEYS \ @@ -21,6 +25,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/model_T2B1_layout.c b/core/embed/models/T2B1/model_T2B1_layout.c similarity index 100% rename from core/embed/models/model_T2B1_layout.c rename to core/embed/models/T2B1/model_T2B1_layout.c diff --git a/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/T2B1/vendorheader/vendor_dev_DO_NOT_SIGN.json similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.json rename to core/embed/models/T2B1/vendorheader/vendor_dev_DO_NOT_SIGN.json diff --git a/core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/T2B1/vendorheader/vendor_dev_DO_NOT_SIGN.toif similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_dev_DO_NOT_SIGN.toif rename to core/embed/models/T2B1/vendorheader/vendor_dev_DO_NOT_SIGN.toif diff --git a/core/embed/vendorheader/T2B1/vendor_prodtest.json b/core/embed/models/T2B1/vendorheader/vendor_prodtest.json similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_prodtest.json rename to core/embed/models/T2B1/vendorheader/vendor_prodtest.json diff --git a/core/embed/vendorheader/T2B1/vendor_prodtest.toif b/core/embed/models/T2B1/vendorheader/vendor_prodtest.toif similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_prodtest.toif rename to core/embed/models/T2B1/vendorheader/vendor_prodtest.toif diff --git a/core/embed/vendorheader/T2B1/vendor_trezor.json b/core/embed/models/T2B1/vendorheader/vendor_trezor.json similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_trezor.json rename to core/embed/models/T2B1/vendorheader/vendor_trezor.json diff --git a/core/embed/vendorheader/T2B1/vendor_trezor.toif b/core/embed/models/T2B1/vendorheader/vendor_trezor.toif similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_trezor.toif rename to core/embed/models/T2B1/vendorheader/vendor_trezor.toif diff --git a/core/embed/vendorheader/T2B1/vendor_trezor_btconly.json b/core/embed/models/T2B1/vendorheader/vendor_trezor_btconly.json similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_trezor_btconly.json rename to core/embed/models/T2B1/vendorheader/vendor_trezor_btconly.json diff --git a/core/embed/vendorheader/T2B1/vendor_trezor_btconly.toif b/core/embed/models/T2B1/vendorheader/vendor_trezor_btconly.toif similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_trezor_btconly.toif rename to core/embed/models/T2B1/vendorheader/vendor_trezor_btconly.toif diff --git a/core/embed/vendorheader/T2B1/vendor_unsafe.json b/core/embed/models/T2B1/vendorheader/vendor_unsafe.json similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_unsafe.json rename to core/embed/models/T2B1/vendorheader/vendor_unsafe.json diff --git a/core/embed/vendorheader/T2B1/vendor_unsafe.toif b/core/embed/models/T2B1/vendorheader/vendor_unsafe.toif similarity index 100% rename from core/embed/vendorheader/T2B1/vendor_unsafe.toif rename to core/embed/models/T2B1/vendorheader/vendor_unsafe.toif diff --git a/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/T2B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/T2B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_prodtest_signed_prod.bin b/core/embed/models/T2B1/vendorheader/vendorheader_prodtest_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_prodtest_signed_prod.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_prodtest_signed_prod.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin b/core/embed/models/T2B1/vendorheader/vendorheader_prodtest_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_prodtest_unsigned.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_trezor_btconly_signed_prod.bin b/core/embed/models/T2B1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_trezor_btconly_signed_prod.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_trezor_btconly_unsigned.bin b/core/embed/models/T2B1/vendorheader/vendorheader_trezor_btconly_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_trezor_btconly_unsigned.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_trezor_btconly_unsigned.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_trezor_signed_prod.bin b/core/embed/models/T2B1/vendorheader/vendorheader_trezor_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_trezor_signed_prod.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_trezor_signed_prod.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_trezor_unsigned.bin b/core/embed/models/T2B1/vendorheader/vendorheader_trezor_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_trezor_unsigned.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_trezor_unsigned.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_unsafe_signed_dev.bin b/core/embed/models/T2B1/vendorheader/vendorheader_unsafe_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_unsafe_signed_dev.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_unsafe_signed_dev.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_unsafe_signed_prod.bin b/core/embed/models/T2B1/vendorheader/vendorheader_unsafe_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_unsafe_signed_prod.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_unsafe_signed_prod.bin diff --git a/core/embed/vendorheader/T2B1/vendorheader_unsafe_unsigned.bin b/core/embed/models/T2B1/vendorheader/vendorheader_unsafe_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2B1/vendorheader_unsafe_unsigned.bin rename to core/embed/models/T2B1/vendorheader/vendorheader_unsafe_unsigned.bin diff --git a/core/embed/models/T2B1/versions.h b/core/embed/models/T2B1/versions.h new file mode 100644 index 0000000000..6329ad6138 --- /dev/null +++ b/core/embed/models/T2B1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 3 +#define FIRMWARE_MONOTONIC_VERSION 2 diff --git a/core/embed/trezorhal/unix/background_T.h b/core/embed/models/T2T1/background_T.h similarity index 100% rename from core/embed/trezorhal/unix/background_T.h rename to core/embed/models/T2T1/background_T.h diff --git a/core/embed/trezorhal/unix/background_T.jpg b/core/embed/models/T2T1/background_T.jpg similarity index 100% rename from core/embed/trezorhal/unix/background_T.jpg rename to core/embed/models/T2T1/background_T.jpg diff --git a/core/embed/trezorhal/unix/background_raspi.h b/core/embed/models/T2T1/background_raspi.h similarity index 100% rename from core/embed/trezorhal/unix/background_raspi.h rename to core/embed/models/T2T1/background_raspi.h diff --git a/core/embed/trezorhal/unix/background_raspi.jpg b/core/embed/models/T2T1/background_raspi.jpg similarity index 100% rename from core/embed/trezorhal/unix/background_raspi.jpg rename to core/embed/models/T2T1/background_raspi.jpg diff --git a/core/embed/models/T2T1/boards/t2t1-unix.h b/core/embed/models/T2T1/boards/t2t1-unix.h new file mode 100644 index 0000000000..6cc10c6713 --- /dev/null +++ b/core/embed/models/T2T1/boards/t2t1-unix.h @@ -0,0 +1,39 @@ +#ifndef BOARDS_T2T1_UNIX_H +#define BOARDS_T2T1_UNIX_H + +#define USE_TOUCH 1 +#define USE_SD_CARD 1 +#define USE_SBU 1 +#define USE_RGB_COLORS 1 +#define USE_BACKLIGHT 1 + +// ILI9341V, GC9307 and ST7789V drivers support 240px x 320px display resolution +#define MAX_DISPLAY_RESX 240 +#define MAX_DISPLAY_RESY 320 +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define TREZOR_FONT_BPP 4 + +#define ORIENTATION_NSEW 1 + +#ifdef TREZOR_EMULATOR_RASPI +#define WINDOW_WIDTH 480 +#define WINDOW_HEIGHT 320 +#define TOUCH_OFFSET_X 110 +#define TOUCH_OFFSET_Y 40 + +#define BACKGROUND_FILE "background_raspi.h" +#define BACKGROUND_NAME background_raspi_jpg + +#else +#define WINDOW_WIDTH 400 +#define WINDOW_HEIGHT 600 +#define TOUCH_OFFSET_X 80 +#define TOUCH_OFFSET_Y 110 + +#define BACKGROUND_FILE "T2T1/background_T.h" +#define BACKGROUND_NAME background_T_jpg + +#endif + +#endif // BOARDS_T2T1_UNIX_H diff --git a/core/embed/trezorhal/boards/trezor_t.h b/core/embed/models/T2T1/boards/trezor_t.h similarity index 92% rename from core/embed/trezorhal/boards/trezor_t.h rename to core/embed/models/T2T1/boards/trezor_t.h index 557f8bb55c..14e2ffd3ff 100644 --- a/core/embed/trezorhal/boards/trezor_t.h +++ b/core/embed/models/T2T1/boards/trezor_t.h @@ -3,9 +3,6 @@ #define HSE_8MHZ -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define USE_SD_CARD 1 #define USE_I2C 1 #define USE_TOUCH 1 @@ -14,12 +11,14 @@ #define USE_BACKLIGHT 1 #define USE_DISP_I8080_8BIT_DW 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 -#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords #define BACKLIGHT_PWM_FREQ 10000 #define BACKLIGHT_PWM_TIM TIM1 diff --git a/core/embed/firmware/bootloaders/bootloader_T2T1.bin b/core/embed/models/T2T1/bootloaders/bootloader_T2T1.bin similarity index 100% rename from core/embed/firmware/bootloaders/bootloader_T2T1.bin rename to core/embed/models/T2T1/bootloaders/bootloader_T2T1.bin diff --git a/core/embed/firmware/bootloaders/bootloader_T2T1_qa.bin b/core/embed/models/T2T1/bootloaders/bootloader_T2T1_qa.bin similarity index 100% rename from core/embed/firmware/bootloaders/bootloader_T2T1_qa.bin rename to core/embed/models/T2T1/bootloaders/bootloader_T2T1_qa.bin diff --git a/core/embed/models/T2T1/bootloaders/bootloader_hashes.h b/core/embed/models/T2T1/bootloaders/bootloader_hashes.h new file mode 100644 index 0000000000..de3db66f3d --- /dev/null +++ b/core/embed/models/T2T1/bootloaders/bootloader_hashes.h @@ -0,0 +1,17 @@ +#ifndef BOOTLOADER_HASHES_H +#define BOOTLOADER_HASHES_H + +// Auto-generated file, do not edit. + +// clang-format off +// bootloader_T2T1.bin version 2.1.4.0 +#define BOOTLOADER_T2T1_00 {0x37, 0xaf, 0xad, 0xb6, 0x55, 0x7a, 0xd3, 0x82, 0x2c, 0x7b, 0xd3, 0x41, 0x65, 0xb7, 0x4d, 0xce, 0xbe, 0x23, 0x87, 0x90, 0x93, 0x3f, 0xbc, 0x4c, 0x5a, 0x1c, 0x60, 0x8c, 0xf9, 0xf6, 0xec, 0x0c} +#define BOOTLOADER_T2T1_FF {0x5e, 0x84, 0xd3, 0xf7, 0xfd, 0x55, 0x51, 0xfd, 0x5f, 0x22, 0xc4, 0x83, 0xe2, 0x67, 0xc5, 0x1b, 0x77, 0xce, 0x49, 0xce, 0x42, 0x19, 0xe8, 0x23, 0x84, 0x4a, 0x58, 0x47, 0xaf, 0x80, 0x69, 0x86} + +// bootloader_T2T1_qa.bin version 2.1.4.0 +#define BOOTLOADER_T2T1_QA_00 {0xff, 0xda, 0xfd, 0x0f, 0xe1, 0x89, 0x56, 0xb6, 0x0b, 0x6e, 0x2d, 0x67, 0xf1, 0x63, 0x8c, 0x4c, 0x4d, 0x6f, 0x97, 0xe7, 0xe0, 0xa4, 0xce, 0x76, 0xc9, 0x49, 0x0a, 0x34, 0x3e, 0xd8, 0xcb, 0x1f} +#define BOOTLOADER_T2T1_QA_FF {0xbe, 0x31, 0x71, 0x7b, 0x8b, 0x31, 0x12, 0xbd, 0x58, 0xc4, 0x81, 0x09, 0x8d, 0xd9, 0x07, 0x51, 0x5c, 0xb6, 0x3d, 0x07, 0x82, 0x00, 0x30, 0x4a, 0xeb, 0x26, 0xf0, 0xe4, 0x00, 0xd4, 0xf2, 0x9c} + +// clang-format on + +#endif diff --git a/core/embed/models/model_T2T1.h b/core/embed/models/T2T1/model_T2T1.h similarity index 93% rename from core/embed/models/model_T2T1.h rename to core/embed/models/T2T1/model_T2T1.h index 1af939a55b..fc29eaf94c 100644 --- a/core/embed/models/model_T2T1.h +++ b/core/embed/models/T2T1/model_T2T1.h @@ -1,11 +1,15 @@ #ifndef MODELS_MODEL_T2T1_H_ #define MODELS_MODEL_T2T1_H_ +#include "bootloaders/bootloader_hashes.h" + #define MODEL_NAME "T" #define MODEL_FULL_NAME "Trezor Model T" #define MODEL_INTERNAL_NAME "T2T1" #define MODEL_INTERNAL_NAME_TOKEN T2T1 #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T2T1 +#define MODEL_USB_MANUFACTURER "SatoshiLabs" +#define MODEL_USB_PRODUCT "TREZOR" /*** PRODUCTION KEYS ***/ #define MODEL_BOARDLOADER_KEYS \ @@ -21,6 +25,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_BLAKE2S #define BOARD_CAPABILITIES_ADDR 0x0800BF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x08000000 diff --git a/core/embed/models/model_T2T1_layout.c b/core/embed/models/T2T1/model_T2T1_layout.c similarity index 100% rename from core/embed/models/model_T2T1_layout.c rename to core/embed/models/T2T1/model_T2T1_layout.c diff --git a/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/T2T1/vendorheader/vendor_dev_DO_NOT_SIGN.json similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.json rename to core/embed/models/T2T1/vendorheader/vendor_dev_DO_NOT_SIGN.json diff --git a/core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/T2T1/vendorheader/vendor_dev_DO_NOT_SIGN.toif similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_dev_DO_NOT_SIGN.toif rename to core/embed/models/T2T1/vendorheader/vendor_dev_DO_NOT_SIGN.toif diff --git a/core/embed/vendorheader/T2T1/vendor_prodtest.json b/core/embed/models/T2T1/vendorheader/vendor_prodtest.json similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_prodtest.json rename to core/embed/models/T2T1/vendorheader/vendor_prodtest.json diff --git a/core/embed/vendorheader/T2T1/vendor_prodtest.toif b/core/embed/models/T2T1/vendorheader/vendor_prodtest.toif similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_prodtest.toif rename to core/embed/models/T2T1/vendorheader/vendor_prodtest.toif diff --git a/core/embed/vendorheader/T2T1/vendor_satoshilabs.json b/core/embed/models/T2T1/vendorheader/vendor_satoshilabs.json similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_satoshilabs.json rename to core/embed/models/T2T1/vendorheader/vendor_satoshilabs.json diff --git a/core/embed/vendorheader/T2T1/vendor_satoshilabs.toif b/core/embed/models/T2T1/vendorheader/vendor_satoshilabs.toif similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_satoshilabs.toif rename to core/embed/models/T2T1/vendorheader/vendor_satoshilabs.toif diff --git a/core/embed/vendorheader/T2T1/vendor_unsafe.json b/core/embed/models/T2T1/vendorheader/vendor_unsafe.json similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_unsafe.json rename to core/embed/models/T2T1/vendorheader/vendor_unsafe.json diff --git a/core/embed/vendorheader/T2T1/vendor_unsafe.toif b/core/embed/models/T2T1/vendorheader/vendor_unsafe.toif similarity index 100% rename from core/embed/vendorheader/T2T1/vendor_unsafe.toif rename to core/embed/models/T2T1/vendorheader/vendor_unsafe.toif diff --git a/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/T2T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/T2T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_prodtest_signed_prod.bin b/core/embed/models/T2T1/vendorheader/vendorheader_prodtest_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_prodtest_signed_prod.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_prodtest_signed_prod.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_prodtest_unsigned.bin b/core/embed/models/T2T1/vendorheader/vendorheader_prodtest_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_prodtest_unsigned.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_prodtest_unsigned.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_satoshilabs_signed_prod.bin b/core/embed/models/T2T1/vendorheader/vendorheader_satoshilabs_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_satoshilabs_signed_prod.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_satoshilabs_signed_prod.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_satoshilabs_unsigned.bin b/core/embed/models/T2T1/vendorheader/vendorheader_satoshilabs_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_satoshilabs_unsigned.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_satoshilabs_unsigned.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_unsafe_signed_dev.bin b/core/embed/models/T2T1/vendorheader/vendorheader_unsafe_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_unsafe_signed_dev.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_unsafe_signed_dev.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_unsafe_signed_prod.bin b/core/embed/models/T2T1/vendorheader/vendorheader_unsafe_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_unsafe_signed_prod.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_unsafe_signed_prod.bin diff --git a/core/embed/vendorheader/T2T1/vendorheader_unsafe_unsigned.bin b/core/embed/models/T2T1/vendorheader/vendorheader_unsafe_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T2T1/vendorheader_unsafe_unsigned.bin rename to core/embed/models/T2T1/vendorheader/vendorheader_unsafe_unsigned.bin diff --git a/core/embed/models/T2T1/versions.h b/core/embed/models/T2T1/versions.h new file mode 100644 index 0000000000..546ca6a16b --- /dev/null +++ b/core/embed/models/T2T1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 2 +#define FIRMWARE_MONOTONIC_VERSION 2 diff --git a/core/embed/models/T3B1/boards/t3b1-unix.h b/core/embed/models/T3B1/boards/t3b1-unix.h new file mode 100644 index 0000000000..ee0871d40c --- /dev/null +++ b/core/embed/models/T3B1/boards/t3b1-unix.h @@ -0,0 +1,24 @@ +#ifndef BOARDS_T3B1_UNIX_H +#define BOARDS_T3B1_UNIX_H + +#define USE_BUTTON 1 +#define USE_SBU 1 +#define USE_OPTIGA 1 + +#define MAX_DISPLAY_RESX 128 +#define MAX_DISPLAY_RESY 64 +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 +#define TREZOR_FONT_BPP 1 + +#define WINDOW_WIDTH 193 +#define WINDOW_HEIGHT 339 +#define TOUCH_OFFSET_X 32 +#define TOUCH_OFFSET_Y 84 + +#define ORIENTATION_NS 1 + +#define BACKGROUND_FILE "T2B1/background_T2B1.h" +#define BACKGROUND_NAME background_T2B1_png + +#endif // BOARDS_T2B1_UNIX_H diff --git a/core/embed/models/T3B1/boards/trezor_t3b1_revB.h b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h new file mode 100644 index 0000000000..e91a2952d2 --- /dev/null +++ b/core/embed/models/T3B1/boards/trezor_t3b1_revB.h @@ -0,0 +1,63 @@ +#ifndef _TREZOR_T3B1_H +#define _TREZOR_T3B1_H + +#define DISPLAY_RESX 128 +#define DISPLAY_RESY 64 + +#define VDD_3V3 1 + +#define USE_I2C 1 +#define USE_BUTTON 1 +#define USE_SBU 1 +#define USE_HASH_PROCESSOR 1 +#define USE_CONSUMPTION_MASK 1 + +#define DISPLAY_LEGACY_HEADER "displays/vg-2864ksweg01.h" + +#define BTN_LEFT_PIN GPIO_PIN_11 +#define BTN_LEFT_PORT GPIOC +#define BTN_LEFT_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define BTN_RIGHT_PIN GPIO_PIN_10 +#define BTN_RIGHT_PORT GPIOD +#define BTN_RIGHT_CLK_ENA __HAL_RCC_GPIOD_CLK_ENABLE + +#define OLED_DC_PORT GPIOC +#define OLED_DC_PIN GPIO_PIN_8 // Data/Command +#define OLED_DC_CLK_ENA __HAL_RCC_GPIOC_CLK_ENABLE +#define OLED_CS_PORT GPIOG +#define OLED_CS_PIN GPIO_PIN_5 // SPI Select +#define OLED_CS_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE +#define OLED_RST_PORT GPIOG +#define OLED_RST_PIN GPIO_PIN_8 // Reset display +#define OLED_RST_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE + +#define OLED_SPI SPI1 +#define OLED_SPI_AF GPIO_AF5_SPI1 +#define OLED_SPI_CLK_ENA __HAL_RCC_SPI1_CLK_ENABLE +#define OLED_SPI_SCK_PORT GPIOG +#define OLED_SPI_SCK_PIN GPIO_PIN_2 // SPI SCK +#define OLED_SPI_SCK_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE +#define OLED_SPI_MOSI_PORT GPIOG +#define OLED_SPI_MOSI_PIN GPIO_PIN_4 // SPI MOSI +#define OLED_SPI_MOSI_CLK_ENA __HAL_RCC_GPIOG_CLK_ENABLE + +#define I2C_COUNT 1 +#define I2C_INSTANCE_0 I2C1 +#define I2C_INSTANCE_0_CLK_EN __HAL_RCC_I2C1_CLK_ENABLE +#define I2C_INSTANCE_0_CLK_DIS __HAL_RCC_I2C1_CLK_DISABLE +#define I2C_INSTANCE_0_PIN_AF GPIO_AF4_I2C1 +#define I2C_INSTANCE_0_SDA_PORT GPIOG +#define I2C_INSTANCE_0_SDA_PIN GPIO_PIN_13 +#define I2C_INSTANCE_0_SDA_CLK_EN __HAL_RCC_GPIOG_CLK_ENABLE +#define I2C_INSTANCE_0_SCL_PORT GPIOG +#define I2C_INSTANCE_0_SCL_PIN GPIO_PIN_14 +#define I2C_INSTANCE_0_SCL_CLK_EN __HAL_RCC_GPIOG_CLK_ENABLE +#define I2C_INSTANCE_0_RESET_REG &RCC->APB1RSTR1 +#define I2C_INSTANCE_0_RESET_BIT RCC_APB1RSTR1_I2C1RST + +#define OPTIGA_I2C_INSTANCE 0 +#define OPTIGA_RST_PORT GPIOE +#define OPTIGA_RST_PIN GPIO_PIN_13 +#define OPTIGA_RST_CLK_EN __HAL_RCC_GPIOE_CLK_ENABLE + +#endif //_TREZOR_T3B1_H diff --git a/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin b/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin new file mode 100644 index 0000000000..034d5c954a Binary files /dev/null and b/core/embed/models/T3B1/bootloaders/bootloader_T3B1.bin differ diff --git a/core/embed/models/T3B1/bootloaders/bootloader_T3B1_qa.bin b/core/embed/models/T3B1/bootloaders/bootloader_T3B1_qa.bin new file mode 100755 index 0000000000..dfd4cce143 Binary files /dev/null and b/core/embed/models/T3B1/bootloaders/bootloader_T3B1_qa.bin differ diff --git a/core/embed/models/T3B1/bootloaders/bootloader_hashes.h b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h new file mode 100644 index 0000000000..e01f324ce0 --- /dev/null +++ b/core/embed/models/T3B1/bootloaders/bootloader_hashes.h @@ -0,0 +1,17 @@ +#ifndef BOOTLOADER_HASHES_H +#define BOOTLOADER_HASHES_H + +// Auto-generated file, do not edit. + +// clang-format off +// bootloader_T3B1.bin version 2.1.7.0 +#define BOOTLOADER_T3B1_00 {0x6a, 0x29, 0x58, 0x1f, 0x4f, 0x0c, 0x64, 0xd0, 0x57, 0xb3, 0x36, 0xb7, 0xca, 0xc5, 0x00, 0xc6, 0xbe, 0x87, 0x46, 0x10, 0x48, 0xb0, 0x20, 0xc5, 0xc3, 0x55, 0xaa, 0xf8, 0xec, 0x48, 0xd6, 0xa3} +#define BOOTLOADER_T3B1_FF {0x57, 0x1e, 0xa2, 0xb8, 0x09, 0xf0, 0xab, 0xb4, 0x35, 0xb9, 0x92, 0xcd, 0xde, 0x28, 0x8a, 0xe2, 0x73, 0x04, 0x92, 0x16, 0x01, 0xac, 0x70, 0x48, 0xad, 0x1d, 0x72, 0x9e, 0x31, 0x42, 0xbf, 0x37} + +// bootloader_T3B1_qa.bin version 2.1.7.0 +#define BOOTLOADER_T3B1_QA_00 {0x2e, 0x90, 0x8a, 0x99, 0x25, 0x93, 0xcd, 0x9c, 0xf1, 0x23, 0x1e, 0x4e, 0x41, 0xfc, 0xc9, 0xf1, 0x4b, 0x06, 0x69, 0x57, 0x6e, 0x64, 0x84, 0x1c, 0xb1, 0xd9, 0x89, 0x0c, 0xa5, 0xb4, 0x38, 0xeb} +#define BOOTLOADER_T3B1_QA_FF {0x63, 0xd2, 0x2d, 0x7b, 0xe8, 0x17, 0x2b, 0x97, 0x64, 0x06, 0x9b, 0x60, 0xa0, 0x3d, 0xfc, 0xd6, 0xea, 0x8a, 0x8d, 0xaf, 0x12, 0x25, 0x58, 0x93, 0x9e, 0x40, 0x16, 0xf2, 0x25, 0x30, 0x30, 0x6f} + +// clang-format on + +#endif diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h new file mode 100644 index 0000000000..3e973c8ff5 --- /dev/null +++ b/core/embed/models/T3B1/model_T3B1.h @@ -0,0 +1,53 @@ +#ifndef MODELS_MODEL_T3B1_H_ +#define MODELS_MODEL_T3B1_H_ + +#include "bootloaders/bootloader_hashes.h" + +#include "sizedefs.h" + +#define MODEL_NAME "Safe 3" +#define MODEL_FULL_NAME "Trezor Safe 3" +#define MODEL_INTERNAL_NAME "T3B1" +#define MODEL_INTERNAL_NAME_TOKEN T3B1 +#define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T3B1 +#define MODEL_USB_MANUFACTURER "Trezor Company" +#define MODEL_USB_PRODUCT MODEL_FULL_NAME + +#define MODEL_BOARDLOADER_KEYS \ + (const uint8_t *)"\xbb\xc2\x1a\xdb\xc1\xb4\x4d\x6b\xfe\x10\xc5\x22\x3d\xe3\x3c\x28\x42\x9e\x52\x68\x07\x07\xd3\x24\x90\x07\xed\x42\xdc\xc5\xbe\x13", \ + (const uint8_t *)"\x22\xe4\x2a\x30\x1f\x3b\x6f\xf4\xf2\xe6\x92\x6b\xce\x43\x59\xe8\x3f\xc8\x3f\x0f\x4a\x84\xa7\x33\x89\x59\xc1\xfd\x0e\x29\xdc\x13", \ + (const uint8_t *)"\x7f\x47\x8f\x5f\xb7\x8d\x8c\x05\x4b\x72\x0d\x81\x04\xbf\x2f\x64\x87\xe4\x52\x40\x24\x58\x97\x9b\x55\x25\xc2\x90\xdc\x34\x4d\x32", + +#define MODEL_BOOTLOADER_KEYS \ + (const uint8_t *)"\x41\xd9\x88\x48\x01\x37\x7c\xff\x04\xb0\xb4\x59\xfc\x9b\x56\xaf\x1b\x51\xf4\x73\x43\xa3\xa6\xe4\xfd\xc1\xea\xca\xbc\xad\x77\x56", \ + (const uint8_t *)"\x23\xec\x4e\xc4\x67\x4d\x68\xac\x54\x31\xe8\xba\x84\xd7\xac\x24\xcb\x5a\x66\x70\x2e\xc5\x65\x01\x4d\x16\x4a\x72\x18\x2a\x66\xc7", \ + (const uint8_t *)"\x8a\x7d\xac\x53\xe1\xbe\x46\x60\x72\x31\x92\x0b\x0c\x71\x05\x6a\x27\xbe\x16\xb6\x7a\x2f\xc0\xd8\x64\x4d\x5f\x87\x08\xa2\x8d\xd1", + +#define IMAGE_CHUNK_SIZE (128 * 1024) +#define IMAGE_HASH_SHA256 +#define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 + +// SHARED WITH MAKEFILE +#define FLASH_START 0x0C000000 +#define BOARDLOADER_START 0x0C004000 +#define BOOTLOADER_START 0x0C010000 +#define FIRMWARE_START 0x0C050000 +#define STORAGE_1_OFFSET 0x30000 +#define STORAGE_2_OFFSET 0x50000 +#define NORCOW_SECTOR_SIZE (8 * 8 * 1024) // 64 kB +#define BOARDLOADER_IMAGE_MAXSIZE (6 * 8 * 1024) // 48 kB +#define BOOTLOADER_IMAGE_MAXSIZE (16 * 8 * 1024) // 128 kB +#define FIRMWARE_IMAGE_MAXSIZE (208 * 8 * 1024) // 1664 kB +#define BOARDLOADER_SECTOR_START 0x2 +#define BOARDLOADER_SECTOR_END 0x7 +#define BOOTLOADER_SECTOR_START 0x8 +#define BOOTLOADER_SECTOR_END 0x17 +#define FIRMWARE_SECTOR_START 0x28 +#define FIRMWARE_SECTOR_END 0xF7 +#define STORAGE_1_SECTOR_START 0x18 +#define STORAGE_1_SECTOR_END 0x1F +#define STORAGE_2_SECTOR_START 0x20 +#define STORAGE_2_SECTOR_END 0x27 + +#endif diff --git a/core/embed/models/model_T3T1_layout.c b/core/embed/models/T3B1/model_T3B1_layout.c similarity index 100% rename from core/embed/models/model_T3T1_layout.c rename to core/embed/models/T3B1/model_T3B1_layout.c diff --git a/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.json new file mode 100644 index 0000000000..7ded76ed4e --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "DEV ONLY, DO NOT USE!", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.toif new file mode 120000 index 0000000000..1fc9443937 --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_dev_DO_NOT_SIGN.toif @@ -0,0 +1 @@ +./vendor_unsafe.toif \ No newline at end of file diff --git a/core/embed/models/T3B1/vendorheader/vendor_prodtest.json b/core/embed/models/T3B1/vendorheader/vendor_prodtest.json new file mode 100644 index 0000000000..ad4be7ce06 --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_prodtest.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "UNSAFE, FACTORY TEST ONLY", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "cf9af91868919da222aaf423386446d5546e165fce0f005e806e3c1a0c2334ec", + "df28cea5a5c557ed56c073c8ddeece1f4c786498efdbb3432ccf93d0af837862", + "27b4374398d4854dc9ade7a500265e1e1d755dfe3b14d207fec76a2f0a0e0529" + ] +} diff --git a/core/embed/models/T3B1/vendorheader/vendor_prodtest.toif b/core/embed/models/T3B1/vendorheader/vendor_prodtest.toif new file mode 120000 index 0000000000..1fc9443937 --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_prodtest.toif @@ -0,0 +1 @@ +./vendor_unsafe.toif \ No newline at end of file diff --git a/core/embed/models/T3B1/vendorheader/vendor_trezor.json b/core/embed/models/T3B1/vendorheader/vendor_trezor.json new file mode 100644 index 0000000000..e9ce3cf43d --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_trezor.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "Trezor", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "90edb45db65f26d793f8b8c6a505062286262d028d341f273272e5d2bcc71f18", + "e32f59de973a39cb2b5ce79a17cbc4107272d46c617848e3c7b19b5b731cc174", + "8a5d0b43591db2dbf3895ce19d30d7ec05333b0028737ab76cacb4b7ed0833fe" + ] +} diff --git a/core/embed/models/T3B1/vendorheader/vendor_trezor.toif b/core/embed/models/T3B1/vendorheader/vendor_trezor.toif new file mode 100644 index 0000000000..60006897dc Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendor_trezor.toif differ diff --git a/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.json b/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.json new file mode 100644 index 0000000000..35112ca2ce --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "Trezor Bitcoin-only", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": true, + "show_vendor_string": false, + "require_user_click": false, + "red_background": false, + "delay": 0 + }, + "pubkeys": [ + "461ccf3ac3f32ced6f8528aef50bacd2687f42c8d1c627ed424fdbb0f6b40041", + "15aed3fcd2fa61e738641d47e77e0a8a83371de2ef6716f9c74f70f16bc76dd8", + "c851f5d5625cfb37c4afb85eee8375b6af5b11e59be115cfa601f795921f280e" + ] +} diff --git a/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.toif b/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.toif new file mode 100644 index 0000000000..1f17ff9b7e Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendor_trezor_btconly.toif differ diff --git a/core/embed/models/T3B1/vendorheader/vendor_unsafe.json b/core/embed/models/T3B1/vendorheader/vendor_unsafe.json new file mode 100644 index 0000000000..5ac4215741 --- /dev/null +++ b/core/embed/models/T3B1/vendorheader/vendor_unsafe.json @@ -0,0 +1,20 @@ +{ + "header_len": 512, + "text": "UNSAFE, DO NOT USE!", + "hw_model": "T3B1", + "expiry": 0, + "version": [0, 0], + "sig_m": 2, + "trust": { + "allow_run_with_secret": false, + "show_vendor_string": true, + "require_user_click": true, + "red_background": true, + "delay": 1 + }, + "pubkeys": [ + "e28a8970753332bd72fef413e6b0b2ef1b4aadda7aa2c141f233712a6876b351", + "d4eec1869fb1b8a4e817516ad5a931557cb56805c3eb16e8f3a803d647df7869", + "772c8a442b7db06e166cfbc1ccbcbcde6f3eba76a4e98ef3ffc519502237d6ef" + ] +} diff --git a/core/embed/models/T3B1/vendorheader/vendor_unsafe.toif b/core/embed/models/T3B1/vendorheader/vendor_unsafe.toif new file mode 100644 index 0000000000..9d302f7335 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendor_unsafe.toif differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin new file mode 100644 index 0000000000..de480c0985 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin new file mode 100644 index 0000000000..1db0c2cd38 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_signed_prod.bin b/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_signed_prod.bin new file mode 100644 index 0000000000..49f5575920 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_signed_prod.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_unsigned.bin b/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_unsigned.bin new file mode 100644 index 0000000000..e5c243ab0f Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_prodtest_unsigned.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin new file mode 100644 index 0000000000..c2efc8727f Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_unsigned.bin b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_unsigned.bin new file mode 100644 index 0000000000..966facd9c5 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_btconly_unsigned.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_trezor_signed_prod.bin b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_signed_prod.bin new file mode 100644 index 0000000000..65d018bd66 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_signed_prod.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_trezor_unsigned.bin b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_unsigned.bin new file mode 100644 index 0000000000..5d6e6ea34e Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_trezor_unsigned.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_dev.bin b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_dev.bin new file mode 100644 index 0000000000..cc04f109c1 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_dev.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_prod.bin b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_prod.bin new file mode 100644 index 0000000000..1a4a2a2333 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_signed_prod.bin differ diff --git a/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_unsigned.bin b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_unsigned.bin new file mode 100644 index 0000000000..8d69feb9f2 Binary files /dev/null and b/core/embed/models/T3B1/vendorheader/vendorheader_unsafe_unsigned.bin differ diff --git a/core/embed/models/T3B1/versions.h b/core/embed/models/T3B1/versions.h new file mode 100644 index 0000000000..5ccdcb89ec --- /dev/null +++ b/core/embed/models/T3B1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 2 +#define FIRMWARE_MONOTONIC_VERSION 1 diff --git a/core/embed/trezorhal/boards/Clocks_T3T1_revE.md b/core/embed/models/T3T1/Clocks_T3T1_revE.md similarity index 100% rename from core/embed/trezorhal/boards/Clocks_T3T1_revE.md rename to core/embed/models/T3T1/Clocks_T3T1_revE.md diff --git a/core/embed/models/T3T1/background_T3T1.h b/core/embed/models/T3T1/background_T3T1.h new file mode 100644 index 0000000000..276961066e --- /dev/null +++ b/core/embed/models/T3T1/background_T3T1.h @@ -0,0 +1,4219 @@ +// clang-format off +unsigned char background_T3T1_jpg[] = { + 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, + 0x01, 0x02, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0xff, 0xe1, 0x0e, 0x10, + 0x45, 0x78, 0x69, 0x66, 0x00, 0x00, 0x49, 0x49, 0x2a, 0x00, 0x08, 0x00, + 0x00, 0x00, 0x07, 0x00, 0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x1a, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x62, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x6a, 0x00, 0x00, 0x00, 0x28, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x31, 0x01, 0x02, 0x00, 0x0d, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x32, 0x01, 0x02, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x69, 0x87, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x94, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x37, 0x02, 0x00, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x37, 0x02, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x47, 0x49, 0x4d, 0x50, 0x20, 0x32, 0x2e, 0x31, 0x30, 0x2e, 0x33, 0x30, + 0x00, 0x00, 0x32, 0x30, 0x32, 0x34, 0x3a, 0x30, 0x37, 0x3a, 0x31, 0x31, + 0x20, 0x32, 0x31, 0x3a, 0x34, 0x37, 0x3a, 0x33, 0x34, 0x00, 0x01, 0x00, + 0x01, 0xa0, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0xfe, 0x00, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x01, 0x03, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x03, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x15, 0x01, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x02, 0x02, 0x04, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xe9, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0x08, 0x00, 0x08, 0x00, 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, + 0x49, 0x46, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, + 0xff, 0xdb, 0x00, 0x43, 0x00, 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, + 0x07, 0x07, 0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0d, 0x0c, 0x0b, + 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f, 0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, + 0x1a, 0x1c, 0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c, 0x23, 0x1c, + 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30, 0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, + 0x39, 0x3d, 0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0xff, 0xdb, 0x00, + 0x43, 0x01, 0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0d, 0x0d, 0x18, + 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x01, + 0x00, 0x00, 0xaa, 0x03, 0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, + 0x01, 0xff, 0xc4, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, + 0x00, 0xb5, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, + 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, 0x01, 0x02, 0x03, 0x00, 0x04, + 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, + 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, + 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, + 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, + 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, + 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, + 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, + 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, + 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, + 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xc4, 0x00, 0x1f, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff, 0xc4, + 0x00, 0xb5, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, + 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, + 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, + 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, + 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, + 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, + 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, + 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, + 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, + 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, + 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, + 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, + 0x00, 0x3f, 0x00, 0xf4, 0xca, 0x28, 0xaa, 0xda, 0x85, 0xfc, 0x1a, 0x6d, + 0x8c, 0xb7, 0x77, 0x2d, 0xb6, 0x28, 0xd7, 0x27, 0xdf, 0xda, 0xac, 0x82, + 0xcd, 0x34, 0xc8, 0x83, 0xab, 0xa8, 0xfa, 0x9a, 0xf0, 0xcf, 0x13, 0xfc, + 0x4a, 0xd4, 0xae, 0xa7, 0x64, 0xb7, 0x94, 0xc1, 0x16, 0x7e, 0x58, 0xe3, + 0x38, 0x38, 0xf7, 0x35, 0xc8, 0xcb, 0xe2, 0x7b, 0xf9, 0xb3, 0xe6, 0x4d, + 0x2b, 0x1f, 0x79, 0x33, 0xfc, 0xc5, 0x2e, 0x61, 0xd8, 0xfa, 0x79, 0xae, + 0xad, 0xd3, 0xef, 0x4f, 0x18, 0xfa, 0xb0, 0xa8, 0x9b, 0x52, 0xb1, 0x4f, + 0xbd, 0x79, 0x00, 0xfa, 0xc8, 0x2b, 0xe5, 0xd3, 0xad, 0xde, 0x76, 0x7f, + 0xce, 0x9a, 0x75, 0x9b, 0xc2, 0x7f, 0xd6, 0x0a, 0x39, 0x87, 0x63, 0xe9, + 0xf3, 0xad, 0xe9, 0x4b, 0xf7, 0xb5, 0x2b, 0x41, 0xf5, 0x99, 0x7f, 0xc6, + 0x98, 0x7c, 0x41, 0xa3, 0x0e, 0xba, 0xa5, 0x9f, 0xfd, 0xfe, 0x5f, 0xf1, + 0xaf, 0x98, 0x4e, 0xad, 0x76, 0x7f, 0xe5, 0xa6, 0x3f, 0x3a, 0x41, 0xa9, + 0xdd, 0x13, 0xfe, 0xb4, 0xd1, 0xcc, 0x16, 0x3e, 0x9d, 0x3e, 0x24, 0xd1, + 0x47, 0xfc, 0xc5, 0x2d, 0x7f, 0xef, 0xe0, 0xa4, 0x3e, 0x26, 0xd1, 0x07, + 0xfc, 0xc4, 0xed, 0xbf, 0xef, 0xba, 0xf9, 0x9d, 0x75, 0x0b, 0x93, 0xff, + 0x00, 0x2d, 0x9a, 0xa6, 0x5b, 0xc9, 0xcf, 0x59, 0x0d, 0x2e, 0x60, 0xb1, + 0xf4, 0x8f, 0xfc, 0x24, 0xfa, 0x27, 0xfd, 0x04, 0xed, 0xff, 0x00, 0xef, + 0xaa, 0x51, 0xe2, 0x5d, 0x10, 0xff, 0x00, 0xcc, 0x4e, 0xdb, 0xfe, 0xfb, + 0xaf, 0x9d, 0x12, 0xe2, 0x43, 0xd5, 0xdb, 0xf3, 0xab, 0x09, 0x23, 0x1e, + 0xac, 0x7f, 0x3a, 0x39, 0x82, 0xc7, 0xd0, 0xa3, 0xc4, 0x7a, 0x29, 0xff, + 0x00, 0x98, 0xa5, 0xaf, 0xfd, 0xfd, 0x14, 0xa3, 0xc4, 0x1a, 0x31, 0xff, + 0x00, 0x98, 0xa5, 0x9f, 0xfd, 0xfe, 0x5f, 0xf1, 0xaf, 0x02, 0x4c, 0x37, + 0x52, 0xdf, 0x99, 0xa9, 0x84, 0x48, 0x7f, 0xbd, 0xff, 0x00, 0x7d, 0x9f, + 0xf1, 0xa3, 0x98, 0x2c, 0x7b, 0xca, 0xeb, 0x9a, 0x4b, 0x7d, 0xdd, 0x4e, + 0xcc, 0xfd, 0x26, 0x5f, 0xf1, 0xa9, 0x97, 0x52, 0xb1, 0x7f, 0xbb, 0x79, + 0x03, 0x7d, 0x24, 0x15, 0xe0, 0x22, 0x24, 0x1d, 0x37, 0x7f, 0xdf, 0x67, + 0xfc, 0x69, 0x76, 0x7a, 0x33, 0x8f, 0xf8, 0x11, 0xa7, 0xcc, 0x16, 0x3e, + 0x82, 0x5b, 0xab, 0x76, 0xfb, 0xb3, 0xc6, 0x7e, 0x8c, 0x29, 0xde, 0x6c, + 0x7f, 0xf3, 0xd1, 0x7f, 0x3a, 0xf9, 0xf3, 0x0d, 0xda, 0x47, 0x1f, 0x8d, + 0x2a, 0xbc, 0xc9, 0xf7, 0x2e, 0xa6, 0x1f, 0xf0, 0x21, 0xfe, 0x14, 0x73, + 0x05, 0x8f, 0xa1, 0x41, 0x04, 0x64, 0x1c, 0xd1, 0x5e, 0x15, 0x63, 0xe2, + 0x0d, 0x67, 0x4d, 0x94, 0x3d, 0xbd, 0xfc, 0x8c, 0x07, 0xf0, 0x39, 0xc8, + 0x3f, 0x9d, 0x7a, 0xbf, 0x85, 0xbc, 0x49, 0x17, 0x88, 0xb4, 0xff, 0x00, + 0x30, 0xa8, 0x8e, 0xe6, 0x3e, 0x25, 0x41, 0xeb, 0xea, 0x3d, 0xa9, 0xa6, + 0x2b, 0x1b, 0xd4, 0x51, 0x45, 0x31, 0x05, 0x79, 0xcf, 0xc5, 0xad, 0x45, + 0xed, 0xf4, 0xab, 0x6b, 0x54, 0x62, 0x3c, 0xcd, 0xd2, 0x37, 0xbe, 0x30, + 0x07, 0xf3, 0xaf, 0x46, 0xaf, 0x2a, 0xf8, 0xc5, 0xf7, 0x2c, 0xbf, 0xeb, + 0x8c, 0x9f, 0xcc, 0x52, 0x7b, 0x0d, 0x1e, 0x2e, 0xcc, 0xcc, 0xc5, 0x98, + 0xe5, 0x8f, 0x26, 0x92, 0x8a, 0x33, 0x50, 0x50, 0x51, 0x45, 0x14, 0x00, + 0x52, 0x8a, 0x6d, 0x14, 0x01, 0x32, 0x1a, 0xb0, 0x8d, 0x55, 0x14, 0xd4, + 0xe8, 0x68, 0x02, 0xec, 0x6d, 0x56, 0xa3, 0x6a, 0xa0, 0x8d, 0x56, 0xa3, + 0x6a, 0x00, 0xd0, 0x8d, 0xaa, 0xd2, 0x37, 0x15, 0x9f, 0x1b, 0x55, 0xb8, + 0xda, 0x80, 0x2c, 0x52, 0xd3, 0x41, 0xe2, 0x96, 0x80, 0x0a, 0x29, 0x28, + 0xa0, 0x07, 0x57, 0x41, 0xe0, 0x0b, 0xc7, 0xb5, 0xf1, 0x82, 0x42, 0x18, + 0xec, 0x9c, 0x15, 0x61, 0xff, 0x00, 0x01, 0x27, 0xf9, 0x8a, 0xe7, 0x6b, + 0x5b, 0xc1, 0xbf, 0xf2, 0x3b, 0xd8, 0xff, 0x00, 0xbf, 0xff, 0x00, 0xb2, + 0xb5, 0x08, 0x0f, 0x71, 0xa2, 0x8a, 0x2b, 0x42, 0x02, 0xbc, 0xa7, 0xe3, + 0x1f, 0xdd, 0xb2, 0xff, 0x00, 0xae, 0x32, 0x7f, 0x31, 0x5e, 0xad, 0x5e, + 0x53, 0xf1, 0x93, 0xa5, 0x97, 0xfd, 0x71, 0x93, 0xf9, 0x8a, 0x4f, 0x61, + 0xa3, 0xc5, 0xa8, 0xa2, 0x8a, 0x82, 0x82, 0x8a, 0x85, 0xe6, 0x2a, 0xe4, + 0x00, 0x29, 0xbe, 0x7b, 0x7a, 0x0a, 0x00, 0xb1, 0x45, 0x57, 0xf3, 0xdb, + 0xd0, 0x51, 0xe7, 0xb7, 0xa0, 0xa0, 0x0b, 0x20, 0xd4, 0xaa, 0x6a, 0x97, + 0xda, 0x1b, 0xd0, 0x52, 0x8b, 0xa6, 0x1f, 0xc2, 0x28, 0x03, 0x51, 0x1a, + 0xac, 0xc6, 0xd5, 0x8a, 0x2f, 0x9c, 0x7f, 0x0a, 0xd4, 0x8b, 0xa9, 0xb8, + 0xff, 0x00, 0x96, 0x6b, 0xf9, 0xd0, 0x07, 0x41, 0x1b, 0x55, 0xa8, 0xde, + 0xb9, 0x95, 0xd6, 0x24, 0x5f, 0xf9, 0x64, 0xbf, 0x9d, 0x4a, 0xba, 0xf4, + 0xab, 0xff, 0x00, 0x2c, 0x53, 0xf3, 0x34, 0x01, 0xd5, 0x23, 0x54, 0x95, + 0xca, 0xaf, 0x89, 0x26, 0x5f, 0xf9, 0x77, 0x4f, 0xfb, 0xe8, 0xd3, 0xc7, + 0x8a, 0x26, 0xff, 0x00, 0x9f, 0x64, 0xff, 0x00, 0xbe, 0x8d, 0x00, 0x74, + 0xf4, 0x57, 0x31, 0xff, 0x00, 0x09, 0x44, 0xdf, 0xf3, 0xec, 0x9f, 0xf7, + 0xd1, 0xae, 0x9a, 0x80, 0x16, 0xb5, 0x7c, 0x1b, 0xff, 0x00, 0x23, 0xc5, + 0x87, 0xfb, 0xff, 0x00, 0xfb, 0x2b, 0x56, 0x55, 0x6a, 0xf8, 0x37, 0xfe, + 0x47, 0x9b, 0x0f, 0xf7, 0xff, 0x00, 0xf6, 0x56, 0xa1, 0x01, 0xee, 0x54, + 0x51, 0x45, 0x68, 0x40, 0x57, 0x94, 0x7c, 0x64, 0xff, 0x00, 0x97, 0x1f, + 0xfa, 0xe3, 0x27, 0xf3, 0x15, 0xea, 0xf5, 0xe4, 0xff, 0x00, 0x19, 0x7f, + 0xe5, 0xc7, 0xfe, 0xb8, 0xc9, 0xfc, 0xc5, 0x27, 0xb0, 0xd1, 0xe3, 0x14, + 0x52, 0x51, 0x50, 0x51, 0x5a, 0x5f, 0xf5, 0xa6, 0x99, 0x4f, 0x97, 0xfd, + 0x61, 0xa6, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, + 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, + 0x5e, 0x89, 0x5e, 0x77, 0x5e, 0x87, 0xd6, 0x80, 0x16, 0xb5, 0x7c, 0x1d, + 0xff, 0x00, 0x23, 0xd6, 0x9f, 0xfe, 0xff, 0x00, 0xfe, 0xca, 0xd5, 0x95, + 0x5a, 0x9e, 0x0e, 0xff, 0x00, 0x91, 0xeb, 0x4f, 0xff, 0x00, 0x7f, 0xff, + 0x00, 0x65, 0x6a, 0x10, 0x1e, 0xe9, 0x45, 0x14, 0x56, 0x84, 0x05, 0x79, + 0x37, 0xc6, 0x6e, 0xb6, 0x1f, 0xf5, 0xc6, 0x4f, 0xe6, 0x2b, 0xd6, 0x6b, + 0xc9, 0x7e, 0x33, 0x7d, 0xeb, 0x0f, 0xfa, 0xe3, 0x27, 0xf3, 0x5a, 0x4f, + 0x61, 0xa3, 0xc6, 0x28, 0xa4, 0xa2, 0xa0, 0xa2, 0x09, 0x7f, 0xd6, 0x1a, + 0x65, 0x3e, 0x4f, 0xf5, 0x86, 0x99, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, + 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, + 0x14, 0x51, 0x40, 0x05, 0x7a, 0x02, 0xb5, 0x79, 0xfd, 0x77, 0x4a, 0xd4, + 0x01, 0x63, 0x35, 0xab, 0xe0, 0xe3, 0xff, 0x00, 0x15, 0xde, 0x9f, 0xfe, + 0xff, 0x00, 0xfe, 0xca, 0xd5, 0x8c, 0x1a, 0xb5, 0xfc, 0x1a, 0x73, 0xe3, + 0xbd, 0x3b, 0xfd, 0xff, 0x00, 0xfd, 0x95, 0xa8, 0x40, 0x7b, 0xbd, 0x14, + 0x51, 0x5a, 0x10, 0x15, 0xe4, 0xbf, 0x19, 0xfe, 0xf5, 0x87, 0xfd, 0x71, + 0x93, 0xf9, 0xad, 0x7a, 0xd5, 0x79, 0x27, 0xc6, 0x7f, 0xbd, 0xa7, 0xff, + 0x00, 0xd7, 0x19, 0x3f, 0x9a, 0xd2, 0x7b, 0x0d, 0x1e, 0x31, 0x45, 0x14, + 0x54, 0x14, 0x57, 0x93, 0xfd, 0x61, 0xa6, 0xd3, 0xa4, 0xff, 0x00, 0x58, + 0x69, 0xb4, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, + 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x57, + 0x68, 0xad, 0x5c, 0x5d, 0x75, 0xca, 0xd4, 0x01, 0x6c, 0x35, 0x6d, 0x78, + 0x28, 0xe7, 0xc7, 0x7a, 0x77, 0xfb, 0xff, 0x00, 0xfb, 0x2b, 0x57, 0x3e, + 0xad, 0x5b, 0xbe, 0x08, 0x39, 0xf1, 0xd6, 0x9d, 0xfe, 0xff, 0x00, 0xfe, + 0xca, 0xd4, 0x20, 0x3d, 0xf2, 0x8a, 0x28, 0xad, 0x08, 0x0a, 0xf2, 0x3f, + 0x8d, 0x1f, 0x7f, 0x4f, 0xff, 0x00, 0xae, 0x32, 0x7f, 0x35, 0xaf, 0x5c, + 0xaf, 0x23, 0xf8, 0xd3, 0xf7, 0xf4, 0xff, 0x00, 0xfa, 0xe3, 0x27, 0xf3, + 0x5a, 0x4f, 0x61, 0xa3, 0xc6, 0x68, 0xa2, 0x8a, 0x82, 0x8a, 0xf2, 0x7f, + 0xac, 0x34, 0xda, 0x74, 0x9f, 0xeb, 0x0d, 0x36, 0x80, 0x0a, 0x28, 0xa2, + 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, + 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0xea, 0x11, 0xab, 0x97, 0xae, 0x89, + 0x5a, 0x80, 0x2e, 0x2b, 0x57, 0x41, 0xe0, 0x63, 0x9f, 0x1c, 0xe9, 0xdf, + 0xf5, 0xd3, 0xff, 0x00, 0x65, 0x6a, 0xe6, 0x55, 0xab, 0xa4, 0xf0, 0x19, + 0xcf, 0x8e, 0x34, 0xdf, 0xfa, 0xe9, 0xff, 0x00, 0xb2, 0xb5, 0x08, 0x0f, + 0xa0, 0x28, 0xa2, 0x8a, 0xd0, 0x80, 0xaf, 0x22, 0xf8, 0xd3, 0xfe, 0xb3, + 0x4f, 0xff, 0x00, 0xae, 0x32, 0x7f, 0x35, 0xaf, 0x5d, 0xaf, 0x22, 0xf8, + 0xd5, 0xfe, 0xb3, 0x4e, 0xff, 0x00, 0xae, 0x32, 0x7f, 0x35, 0xa4, 0xf6, + 0x1a, 0x3c, 0x66, 0x8a, 0x28, 0xa8, 0x28, 0x82, 0x4f, 0xbe, 0x69, 0xb4, + 0xe9, 0x3e, 0xf9, 0xa6, 0xd0, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, + 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, + 0x50, 0x01, 0x5b, 0xaa, 0xd5, 0x85, 0x5b, 0x0a, 0xd4, 0x01, 0x6d, 0x5a, + 0xba, 0x6f, 0x00, 0x1c, 0xf8, 0xe3, 0x4d, 0xff, 0x00, 0xae, 0x87, 0xff, + 0x00, 0x41, 0x6a, 0xe4, 0xd5, 0xab, 0xaa, 0xf8, 0x7c, 0x73, 0xe3, 0x7d, + 0x37, 0xfe, 0xba, 0x9f, 0xfd, 0x05, 0xa8, 0x40, 0x7d, 0x0b, 0x45, 0x14, + 0x56, 0x84, 0x05, 0x79, 0x0f, 0xc6, 0xaf, 0xf5, 0xba, 0x77, 0xfd, 0x71, + 0x93, 0xf9, 0xad, 0x7a, 0xf5, 0x79, 0x0f, 0xc6, 0xaf, 0xf5, 0xba, 0x6f, + 0xfd, 0x71, 0x97, 0xf9, 0xad, 0x27, 0xb0, 0xd1, 0xe3, 0x54, 0x94, 0x1a, + 0x2a, 0x0a, 0x21, 0x93, 0xef, 0x9a, 0x6d, 0x39, 0xfe, 0xf9, 0xa6, 0xd0, + 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, + 0x01, 0x45, 0x14, 0x50, 0x01, 0x45, 0x14, 0x50, 0x01, 0x5a, 0x6a, 0xd5, + 0x99, 0x57, 0xd4, 0xd0, 0x05, 0x95, 0x6a, 0xeb, 0x7e, 0x1d, 0x9c, 0xf8, + 0xdb, 0x4d, 0xff, 0x00, 0xae, 0xa7, 0xff, 0x00, 0x40, 0x6a, 0xe3, 0x95, + 0xab, 0xaf, 0xf8, 0x72, 0x73, 0xe3, 0x6d, 0x37, 0xfe, 0xba, 0x9f, 0xfd, + 0x01, 0xa8, 0x40, 0x7d, 0x13, 0x45, 0x14, 0x56, 0x84, 0x05, 0x79, 0x37, + 0xc6, 0xa8, 0xc9, 0x8f, 0x4a, 0x90, 0x74, 0x29, 0x32, 0xff, 0x00, 0xe8, + 0x15, 0xeb, 0x35, 0xe7, 0xbf, 0x17, 0xac, 0xcc, 0xfe, 0x1a, 0xb6, 0xb8, + 0x03, 0xfd, 0x4d, 0xc6, 0x09, 0xf4, 0x0c, 0x08, 0xfe, 0x78, 0xa4, 0xf6, + 0x1a, 0x3e, 0x7c, 0xa2, 0x83, 0xc1, 0x20, 0xf6, 0xa4, 0xa8, 0x28, 0x08, + 0x04, 0xf2, 0x29, 0x36, 0x8f, 0x41, 0x4b, 0x45, 0x00, 0x26, 0xd1, 0xe8, + 0x28, 0xda, 0x3d, 0x05, 0x2d, 0x14, 0x00, 0x9b, 0x47, 0xa0, 0xa3, 0x68, + 0xf4, 0x14, 0xb4, 0x50, 0x02, 0x6d, 0x1e, 0x82, 0x8d, 0xa3, 0xd2, 0x96, + 0x8a, 0x00, 0x4d, 0xa3, 0xd2, 0x8d, 0xa3, 0xd2, 0x96, 0x8a, 0x00, 0x4d, + 0xa3, 0xd2, 0x8d, 0xa3, 0xd2, 0x96, 0x8a, 0x00, 0x02, 0xaf, 0xa0, 0xa9, + 0x41, 0xa8, 0xa9, 0xca, 0x68, 0x02, 0xc0, 0x35, 0xda, 0xfc, 0x31, 0x43, + 0x27, 0x8d, 0xf4, 0xdc, 0x0e, 0x8e, 0xe4, 0xfe, 0x11, 0xb5, 0x70, 0xc0, + 0xd7, 0xa7, 0xfc, 0x1c, 0xb4, 0x69, 0x7c, 0x47, 0x25, 0xce, 0xdf, 0x92, + 0x1b, 0x76, 0x39, 0xf4, 0x2c, 0x40, 0x1f, 0xa0, 0x34, 0xd0, 0x33, 0xdc, + 0x68, 0xa2, 0x8a, 0xb2, 0x02, 0xb1, 0x7c, 0x5b, 0xa7, 0x7f, 0x6a, 0xf8, + 0x5b, 0x50, 0xb5, 0x0b, 0xb9, 0xda, 0x22, 0xc8, 0x3f, 0xda, 0x1c, 0x8f, + 0xe5, 0x5b, 0x54, 0x52, 0x03, 0xe4, 0x1b, 0xc8, 0xfc, 0xbb, 0x96, 0xe3, + 0x19, 0xe6, 0xab, 0xd7, 0x67, 0xf1, 0x1b, 0x40, 0x3a, 0x27, 0x89, 0x6e, + 0xa2, 0x45, 0xc4, 0x0e, 0xde, 0x74, 0x3f, 0xee, 0x31, 0xe9, 0xf8, 0x1c, + 0x8a, 0xe3, 0x2a, 0x0b, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, + 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, + 0x0a, 0x28, 0xa2, 0x80, 0x0a, 0x28, 0xa2, 0x80, 0x1e, 0x99, 0x66, 0x0a, + 0x3a, 0x93, 0x8a, 0xf7, 0xef, 0x84, 0x5a, 0x5f, 0xd9, 0x74, 0x1b, 0x8b, + 0xd6, 0x5c, 0x1b, 0x89, 0x36, 0xa1, 0xc7, 0xf0, 0xaf, 0x1f, 0xcf, 0x35, + 0xe1, 0xda, 0x3d, 0x94, 0xb7, 0xda, 0x84, 0x50, 0xc2, 0xbb, 0xa4, 0x76, + 0x08, 0x83, 0xd5, 0x89, 0xc0, 0xaf, 0xaa, 0x34, 0x6d, 0x36, 0x2d, 0x1f, + 0x46, 0xb4, 0xd3, 0xe2, 0xfb, 0xb0, 0x44, 0x13, 0x3f, 0xde, 0x3d, 0xcf, + 0xe2, 0x72, 0x69, 0xa1, 0x32, 0xf5, 0x14, 0x51, 0x56, 0x48, 0x51, 0x45, + 0x14, 0x01, 0xe7, 0xbf, 0x16, 0x74, 0x31, 0x7f, 0xe1, 0xf5, 0xd4, 0x51, + 0x33, 0x25, 0xa1, 0xc3, 0xe0, 0x73, 0xb1, 0xb8, 0x3f, 0x91, 0xc5, 0x7c, + 0xfb, 0x22, 0x18, 0xe4, 0x65, 0x3d, 0x8d, 0x7d, 0x7f, 0x73, 0x6f, 0x15, + 0xdd, 0xac, 0xb6, 0xd3, 0xa0, 0x78, 0xa5, 0x42, 0x8e, 0xa7, 0xa1, 0x04, + 0x60, 0xd7, 0xcb, 0x9e, 0x2c, 0xd1, 0x25, 0xd0, 0xf5, 0xbb, 0x8b, 0x39, + 0x32, 0x7c, 0xa7, 0xda, 0x18, 0xff, 0x00, 0x12, 0xff, 0x00, 0x09, 0xfc, + 0xaa, 0x59, 0x48, 0xc1, 0xa2, 0x8a, 0x2a, 0x46, 0x14, 0x51, 0x45, 0x00, + 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x45, 0x00, + 0x14, 0x51, 0x45, 0x00, 0x14, 0x51, 0x53, 0xda, 0x42, 0x67, 0xb8, 0x55, + 0x00, 0x9e, 0x7a, 0x0e, 0xfe, 0xd4, 0x01, 0xe9, 0xbf, 0x08, 0x34, 0x1f, + 0xb5, 0x6b, 0x0f, 0x7f, 0x2a, 0x66, 0x3b, 0x35, 0xc8, 0x24, 0x71, 0xbd, + 0xba, 0x7e, 0x43, 0x35, 0xee, 0x55, 0xcf, 0x78, 0x2b, 0x42, 0x5f, 0x0f, + 0xf8, 0x66, 0xda, 0xd4, 0xa8, 0x13, 0xc8, 0x3c, 0xd9, 0x8f, 0xab, 0x9f, + 0xf0, 0x18, 0x1f, 0x85, 0x74, 0x35, 0x68, 0x96, 0x14, 0x51, 0x45, 0x31, + 0x05, 0x14, 0x51, 0x40, 0x05, 0x79, 0x57, 0xc6, 0x2f, 0x0f, 0x79, 0xf6, + 0xd0, 0x6b, 0x50, 0xa6, 0x76, 0xfe, 0xe6, 0xe3, 0x03, 0xb1, 0xfb, 0xad, + 0xf9, 0xf1, 0xf8, 0x8a, 0xf5, 0x5a, 0xa9, 0xaa, 0x69, 0xf0, 0xea, 0xba, + 0x65, 0xc5, 0x8c, 0xea, 0x0c, 0x73, 0xa1, 0x43, 0x49, 0x8c, 0xf9, 0x14, + 0x82, 0xac, 0x41, 0xea, 0x29, 0x2b, 0x53, 0x5f, 0xd3, 0x25, 0xd2, 0xb5, + 0x5b, 0x8b, 0x59, 0x94, 0x89, 0x21, 0x90, 0xc6, 0xdf, 0x51, 0xdf, 0xf1, + 0x15, 0x97, 0x50, 0x50, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, + 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, 0x51, 0x45, 0x14, 0x00, + 0x57, 0x7f, 0xf0, 0xbb, 0xc3, 0xa7, 0x58, 0xf1, 0x1c, 0x32, 0x48, 0x99, + 0xb6, 0xb6, 0xfd, 0xfc, 0xa4, 0x8e, 0x0e, 0x3e, 0xea, 0xfe, 0x27, 0x9f, + 0xc0, 0xd7, 0x09, 0x04, 0x7e, 0x6c, 0xa0, 0x76, 0xea, 0x7e, 0x95, 0xf4, + 0xb7, 0xc3, 0xcd, 0x00, 0x68, 0x7e, 0x18, 0x84, 0xc8, 0x9b, 0x6e, 0x6e, + 0xb1, 0x34, 0xb9, 0x1c, 0x8c, 0xf4, 0x1f, 0x80, 0xa6, 0x84, 0xce, 0xb2, + 0x8a, 0x28, 0xab, 0x24, 0x28, 0xa2, 0x8a, 0x00, 0x28, 0xa2, 0x8a, 0x00, + 0x28, 0xa2, 0x8a, 0x00, 0xf2, 0x3f, 0x8c, 0x3e, 0x1a, 0x0e, 0x22, 0xd6, + 0xe0, 0x4c, 0x6e, 0x02, 0x2b, 0x8c, 0x0e, 0xff, 0x00, 0xc2, 0xdf, 0xd3, + 0xf2, 0xaf, 0x16, 0x20, 0x82, 0x41, 0xea, 0x2b, 0xeb, 0x8d, 0x5b, 0x4d, + 0x83, 0x58, 0xd2, 0xae, 0x74, 0xfb, 0x81, 0xfb, 0xb9, 0xd0, 0xa9, 0x3d, + 0xc7, 0xa1, 0x1f, 0x4a, 0xf9, 0x6f, 0xc4, 0x1a, 0x4d, 0xc6, 0x8f, 0xaa, + 0xcf, 0x69, 0x72, 0xb8, 0x96, 0x27, 0x28, 0xde, 0x87, 0xd0, 0x8f, 0x62, + 0x2a, 0x1a, 0x29, 0x19, 0x54, 0x51, 0x45, 0x21, 0x85, 0x14, 0x51, 0x40, + 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x54, 0x90, + 0x44, 0x65, 0x94, 0x2e, 0x38, 0xef, 0x40, 0x1d, 0xa7, 0xc3, 0x6f, 0x0c, + 0xff, 0x00, 0x6e, 0xf8, 0x82, 0x1f, 0x39, 0x37, 0x5b, 0x43, 0x89, 0xa6, + 0xc8, 0xe0, 0x80, 0x78, 0x5f, 0xc4, 0xfe, 0x95, 0xf4, 0x75, 0x72, 0x3f, + 0x0e, 0xfc, 0x39, 0xff, 0x00, 0x08, 0xff, 0x00, 0x86, 0xa3, 0x33, 0x2e, + 0x2f, 0x2e, 0xbf, 0x7b, 0x2f, 0xfb, 0x23, 0xf8, 0x57, 0xf0, 0x1f, 0xae, + 0x6b, 0xae, 0xab, 0x48, 0x96, 0x14, 0x51, 0x45, 0x31, 0x05, 0x14, 0x51, + 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x79, 0x57, + 0xc5, 0xff, 0x00, 0x0d, 0x79, 0xf6, 0xd1, 0xeb, 0x70, 0x47, 0x9d, 0x98, + 0x8a, 0xe3, 0x03, 0xa0, 0xfe, 0x16, 0xfc, 0xf8, 0xfc, 0x6b, 0xd5, 0x6a, + 0x0b, 0xcb, 0x58, 0x6f, 0xac, 0xe6, 0xb5, 0x9d, 0x03, 0xc5, 0x32, 0x14, + 0x75, 0x3d, 0xc1, 0xa4, 0xc6, 0x7c, 0x82, 0xea, 0x51, 0x8a, 0x9e, 0xa2, + 0x92, 0xba, 0x1f, 0x17, 0x68, 0x32, 0xe8, 0x3a, 0xe5, 0xcd, 0x94, 0x80, + 0xfe, 0xed, 0xbe, 0x53, 0xfd, 0xe4, 0x3d, 0x0d, 0x73, 0xd5, 0x05, 0x05, + 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, 0x14, 0x51, 0x40, 0x05, + 0x77, 0xff, 0x00, 0x0c, 0x3c, 0x32, 0x75, 0xaf, 0x10, 0x47, 0x2c, 0xb1, + 0x93, 0x6b, 0x6b, 0x89, 0xa5, 0x27, 0xa6, 0x7f, 0x85, 0x7f, 0x13, 0xcf, + 0xe1, 0x5c, 0x3d, 0xa4, 0x0d, 0x71, 0x3a, 0xa2, 0xa9, 0x62, 0x48, 0x00, + 0x0e, 0xe7, 0xb0, 0xaf, 0xa7, 0xbc, 0x17, 0xe1, 0xe4, 0xf0, 0xe7, 0x87, + 0x60, 0xb5, 0x2a, 0x05, 0xc4, 0x9f, 0xbc, 0x9c, 0xfa, 0xb9, 0x1f, 0xd3, + 0xa5, 0x34, 0x84, 0xce, 0x84, 0x0c, 0x0c, 0x0a, 0x28, 0xa2, 0xac, 0x90, + 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x00, + 0xa2, 0x8a, 0x28, 0x00, 0xa2, 0x8a, 0x28, 0x03, 0x8f, 0xf1, 0xdf, 0x82, + 0xa3, 0xf1, 0x55, 0x8a, 0xcb, 0x06, 0xd8, 0xf5, 0x08, 0x46, 0x23, 0x73, + 0xd1, 0xd7, 0xfb, 0xa6, 0xbc, 0x0f, 0x56, 0xf0, 0xce, 0xa7, 0xa3, 0xdc, + 0x34, 0x57, 0x96, 0x92, 0xc2, 0x41, 0xc0, 0x2c, 0xa7, 0x07, 0xe8, 0x7a, + 0x1a, 0xfa, 0xb2, 0x9a, 0xc8, 0x8e, 0x30, 0xea, 0xac, 0x3d, 0x08, 0xcd, + 0x4b, 0x43, 0x4c, 0xf9, 0x0b, 0xec, 0x92, 0xfb, 0x51, 0xf6, 0x49, 0x7d, + 0xbf, 0x3a, 0xfa, 0xe7, 0xec, 0x76, 0xbf, 0xf3, 0xed, 0x0f, 0xfd, 0xf0, + 0x28, 0xfb, 0x1d, 0xaf, 0xfc, 0xfb, 0x43, 0xff, 0x00, 0x7c, 0x0a, 0x39, + 0x47, 0x73, 0xe4, 0x6f, 0xb2, 0x4b, 0xed, 0xf9, 0xd1, 0xf6, 0x49, 0x3d, + 0xbf, 0x3a, 0xfa, 0xe7, 0xec, 0x76, 0xbf, 0xf3, 0xed, 0x0f, 0xfd, 0xf0, + 0x28, 0xfb, 0x1d, 0xaf, 0xfc, 0xfb, 0x43, 0xff, 0x00, 0x7c, 0x0a, 0x39, + 0x42, 0xe7, 0xc8, 0xdf, 0x64, 0x93, 0xdb, 0xf3, 0xa9, 0xed, 0xb4, 0x9b, + 0xbb, 0xb9, 0x84, 0x50, 0x44, 0xf2, 0xb9, 0xe8, 0xb1, 0xa9, 0x63, 0xfa, + 0x57, 0xd6, 0x5f, 0x63, 0xb5, 0xff, 0x00, 0x9f, 0x68, 0x7f, 0xef, 0x81, + 0x4e, 0x48, 0x22, 0x8b, 0xfd, 0x5c, 0x48, 0x9f, 0xee, 0xa8, 0x14, 0x72, + 0x85, 0xcf, 0x2b, 0xf8, 0x79, 0xf0, 0xda, 0x6b, 0x0b, 0xa8, 0xb5, 0x6d, + 0x62, 0x20, 0x8d, 0x1f, 0xcd, 0x05, 0xbb, 0x72, 0x43, 0x7f, 0x79, 0xbf, + 0xa0, 0xaf, 0x58, 0xa2, 0x8a, 0x62, 0x0a, 0x28, 0xa2, 0x98, 0x82, 0x8a, + 0x28, 0xa0, 0x02, 0x8a, 0x28, 0xa0, 0x0f, 0xff, 0xd9, 0x00, 0xff, 0xe1, + 0x0d, 0x37, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, + 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, + 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x00, 0x3c, 0x3f, 0x78, 0x70, 0x61, + 0x63, 0x6b, 0x65, 0x74, 0x20, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x3d, 0x22, + 0xef, 0xbb, 0xbf, 0x22, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x57, 0x35, 0x4d, + 0x30, 0x4d, 0x70, 0x43, 0x65, 0x68, 0x69, 0x48, 0x7a, 0x72, 0x65, 0x53, + 0x7a, 0x4e, 0x54, 0x63, 0x7a, 0x6b, 0x63, 0x39, 0x64, 0x22, 0x3f, 0x3e, + 0x20, 0x3c, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x20, + 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, 0x78, 0x3d, 0x22, 0x61, 0x64, 0x6f, + 0x62, 0x65, 0x3a, 0x6e, 0x73, 0x3a, 0x6d, 0x65, 0x74, 0x61, 0x2f, 0x22, + 0x20, 0x78, 0x3a, 0x78, 0x6d, 0x70, 0x74, 0x6b, 0x3d, 0x22, 0x58, 0x4d, + 0x50, 0x20, 0x43, 0x6f, 0x72, 0x65, 0x20, 0x34, 0x2e, 0x34, 0x2e, 0x30, + 0x2d, 0x45, 0x78, 0x69, 0x76, 0x32, 0x22, 0x3e, 0x20, 0x3c, 0x72, 0x64, + 0x66, 0x3a, 0x52, 0x44, 0x46, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, + 0x72, 0x64, 0x66, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, + 0x77, 0x77, 0x77, 0x2e, 0x77, 0x33, 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x31, + 0x39, 0x39, 0x39, 0x2f, 0x30, 0x32, 0x2f, 0x32, 0x32, 0x2d, 0x72, 0x64, + 0x66, 0x2d, 0x73, 0x79, 0x6e, 0x74, 0x61, 0x78, 0x2d, 0x6e, 0x73, 0x23, + 0x22, 0x3e, 0x20, 0x3c, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x64, 0x66, 0x3a, + 0x61, 0x62, 0x6f, 0x75, 0x74, 0x3d, 0x22, 0x22, 0x20, 0x78, 0x6d, 0x6c, + 0x6e, 0x73, 0x3a, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3d, 0x22, 0x68, 0x74, + 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, + 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, + 0x30, 0x2f, 0x6d, 0x6d, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, + 0x3a, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, + 0x73, 0x54, 0x79, 0x70, 0x65, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x23, 0x22, 0x20, 0x78, 0x6d, + 0x6c, 0x6e, 0x73, 0x3a, 0x64, 0x63, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, + 0x3a, 0x2f, 0x2f, 0x70, 0x75, 0x72, 0x6c, 0x2e, 0x6f, 0x72, 0x67, 0x2f, + 0x64, 0x63, 0x2f, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x2f, + 0x31, 0x2e, 0x31, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, 0x73, 0x3a, + 0x47, 0x49, 0x4d, 0x50, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x6d, 0x70, 0x2e, 0x6f, 0x72, + 0x67, 0x2f, 0x78, 0x6d, 0x70, 0x2f, 0x22, 0x20, 0x78, 0x6d, 0x6c, 0x6e, + 0x73, 0x3a, 0x78, 0x6d, 0x70, 0x3d, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x6e, 0x73, 0x2e, 0x61, 0x64, 0x6f, 0x62, 0x65, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x78, 0x61, 0x70, 0x2f, 0x31, 0x2e, 0x30, 0x2f, 0x22, + 0x20, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x44, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3d, 0x22, 0x67, 0x69, 0x6d, 0x70, 0x3a, + 0x64, 0x6f, 0x63, 0x69, 0x64, 0x3a, 0x67, 0x69, 0x6d, 0x70, 0x3a, 0x63, + 0x66, 0x37, 0x30, 0x38, 0x33, 0x32, 0x37, 0x2d, 0x66, 0x65, 0x35, 0x32, + 0x2d, 0x34, 0x63, 0x65, 0x61, 0x2d, 0x61, 0x35, 0x35, 0x39, 0x2d, 0x63, + 0x62, 0x63, 0x66, 0x31, 0x35, 0x62, 0x39, 0x65, 0x36, 0x32, 0x38, 0x22, + 0x20, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x49, 0x6e, 0x73, 0x74, 0x61, + 0x6e, 0x63, 0x65, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x69, + 0x69, 0x64, 0x3a, 0x62, 0x30, 0x36, 0x33, 0x31, 0x66, 0x38, 0x63, 0x2d, + 0x64, 0x37, 0x66, 0x66, 0x2d, 0x34, 0x32, 0x66, 0x62, 0x2d, 0x62, 0x30, + 0x39, 0x39, 0x2d, 0x64, 0x31, 0x30, 0x37, 0x30, 0x30, 0x36, 0x38, 0x35, + 0x66, 0x31, 0x65, 0x22, 0x20, 0x78, 0x6d, 0x70, 0x4d, 0x4d, 0x3a, 0x4f, + 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x44, 0x6f, 0x63, 0x75, 0x6d, + 0x65, 0x6e, 0x74, 0x49, 0x44, 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x64, + 0x69, 0x64, 0x3a, 0x63, 0x63, 0x64, 0x34, 0x37, 0x32, 0x33, 0x36, 0x2d, + 0x66, 0x37, 0x31, 0x33, 0x2d, 0x34, 0x64, 0x33, 0x62, 0x2d, 0x38, 0x65, + 0x33, 0x63, 0x2d, 0x66, 0x37, 0x38, 0x37, 0x33, 0x63, 0x36, 0x65, 0x65, + 0x65, 0x63, 0x34, 0x22, 0x20, 0x64, 0x63, 0x3a, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x3d, 0x22, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, + 0x65, 0x67, 0x22, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x3a, 0x41, 0x50, 0x49, + 0x3d, 0x22, 0x32, 0x2e, 0x30, 0x22, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x3a, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x3d, 0x22, 0x4c, 0x69, + 0x6e, 0x75, 0x78, 0x22, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x3a, 0x54, 0x69, + 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70, 0x3d, 0x22, 0x31, 0x37, 0x32, + 0x30, 0x37, 0x32, 0x37, 0x32, 0x36, 0x30, 0x38, 0x31, 0x34, 0x39, 0x32, + 0x39, 0x22, 0x20, 0x47, 0x49, 0x4d, 0x50, 0x3a, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x32, 0x2e, 0x31, 0x30, 0x2e, 0x33, 0x30, + 0x22, 0x20, 0x78, 0x6d, 0x70, 0x3a, 0x43, 0x72, 0x65, 0x61, 0x74, 0x6f, + 0x72, 0x54, 0x6f, 0x6f, 0x6c, 0x3d, 0x22, 0x47, 0x49, 0x4d, 0x50, 0x20, + 0x32, 0x2e, 0x31, 0x30, 0x22, 0x3e, 0x20, 0x3c, 0x78, 0x6d, 0x70, 0x4d, + 0x4d, 0x3a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x3e, 0x20, 0x3c, + 0x72, 0x64, 0x66, 0x3a, 0x53, 0x65, 0x71, 0x3e, 0x20, 0x3c, 0x72, 0x64, + 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x73, 0x61, 0x76, 0x65, 0x64, + 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x3d, 0x22, 0x2f, 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, + 0x74, 0x3a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, + 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x69, 0x69, 0x64, 0x3a, 0x34, 0x38, + 0x37, 0x31, 0x66, 0x34, 0x34, 0x65, 0x2d, 0x31, 0x31, 0x30, 0x64, 0x2d, + 0x34, 0x33, 0x37, 0x63, 0x2d, 0x61, 0x35, 0x66, 0x65, 0x2d, 0x34, 0x34, + 0x38, 0x32, 0x35, 0x63, 0x39, 0x36, 0x37, 0x31, 0x37, 0x34, 0x22, 0x20, + 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x47, 0x69, 0x6d, + 0x70, 0x20, 0x32, 0x2e, 0x31, 0x30, 0x20, 0x28, 0x4c, 0x69, 0x6e, 0x75, + 0x78, 0x29, 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x77, 0x68, + 0x65, 0x6e, 0x3d, 0x22, 0x32, 0x30, 0x32, 0x34, 0x2d, 0x30, 0x37, 0x2d, + 0x31, 0x31, 0x54, 0x30, 0x39, 0x3a, 0x31, 0x38, 0x3a, 0x32, 0x36, 0x2b, + 0x30, 0x32, 0x3a, 0x30, 0x30, 0x22, 0x2f, 0x3e, 0x20, 0x3c, 0x72, 0x64, + 0x66, 0x3a, 0x6c, 0x69, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3d, 0x22, 0x73, 0x61, 0x76, 0x65, 0x64, + 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x3d, 0x22, 0x2f, 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, + 0x74, 0x3a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x44, + 0x3d, 0x22, 0x78, 0x6d, 0x70, 0x2e, 0x69, 0x69, 0x64, 0x3a, 0x37, 0x66, + 0x65, 0x34, 0x31, 0x30, 0x32, 0x66, 0x2d, 0x64, 0x30, 0x61, 0x64, 0x2d, + 0x34, 0x31, 0x31, 0x37, 0x2d, 0x39, 0x31, 0x61, 0x66, 0x2d, 0x64, 0x36, + 0x38, 0x32, 0x34, 0x62, 0x37, 0x38, 0x31, 0x38, 0x38, 0x32, 0x22, 0x20, + 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, + 0x72, 0x65, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3d, 0x22, 0x47, 0x69, 0x6d, + 0x70, 0x20, 0x32, 0x2e, 0x31, 0x30, 0x20, 0x28, 0x4c, 0x69, 0x6e, 0x75, + 0x78, 0x29, 0x22, 0x20, 0x73, 0x74, 0x45, 0x76, 0x74, 0x3a, 0x77, 0x68, + 0x65, 0x6e, 0x3d, 0x22, 0x32, 0x30, 0x32, 0x34, 0x2d, 0x30, 0x37, 0x2d, + 0x31, 0x31, 0x54, 0x32, 0x31, 0x3a, 0x34, 0x37, 0x3a, 0x34, 0x30, 0x2b, + 0x30, 0x32, 0x3a, 0x30, 0x30, 0x22, 0x2f, 0x3e, 0x20, 0x3c, 0x2f, 0x72, + 0x64, 0x66, 0x3a, 0x53, 0x65, 0x71, 0x3e, 0x20, 0x3c, 0x2f, 0x78, 0x6d, + 0x70, 0x4d, 0x4d, 0x3a, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x3e, + 0x20, 0x3c, 0x2f, 0x72, 0x64, 0x66, 0x3a, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x20, 0x3c, 0x2f, 0x72, 0x64, + 0x66, 0x3a, 0x52, 0x44, 0x46, 0x3e, 0x20, 0x3c, 0x2f, 0x78, 0x3a, 0x78, + 0x6d, 0x70, 0x6d, 0x65, 0x74, 0x61, 0x3e, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x3c, 0x3f, 0x78, 0x70, 0x61, 0x63, 0x6b, 0x65, + 0x74, 0x20, 0x65, 0x6e, 0x64, 0x3d, 0x22, 0x77, 0x22, 0x3f, 0x3e, 0xff, + 0xe2, 0x02, 0xb0, 0x49, 0x43, 0x43, 0x5f, 0x50, 0x52, 0x4f, 0x46, 0x49, + 0x4c, 0x45, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0xa0, 0x6c, 0x63, 0x6d, + 0x73, 0x04, 0x30, 0x00, 0x00, 0x6d, 0x6e, 0x74, 0x72, 0x52, 0x47, 0x42, + 0x20, 0x58, 0x59, 0x5a, 0x20, 0x07, 0xe8, 0x00, 0x07, 0x00, 0x0b, 0x00, + 0x13, 0x00, 0x2f, 0x00, 0x0d, 0x61, 0x63, 0x73, 0x70, 0x41, 0x50, 0x50, + 0x4c, 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, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, + 0x2d, 0x6c, 0x63, 0x6d, 0x73, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x64, 0x65, 0x73, 0x63, 0x00, 0x00, 0x01, + 0x20, 0x00, 0x00, 0x00, 0x40, 0x63, 0x70, 0x72, 0x74, 0x00, 0x00, 0x01, + 0x60, 0x00, 0x00, 0x00, 0x36, 0x77, 0x74, 0x70, 0x74, 0x00, 0x00, 0x01, + 0x98, 0x00, 0x00, 0x00, 0x14, 0x63, 0x68, 0x61, 0x64, 0x00, 0x00, 0x01, + 0xac, 0x00, 0x00, 0x00, 0x2c, 0x72, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, + 0xd8, 0x00, 0x00, 0x00, 0x14, 0x62, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x01, + 0xec, 0x00, 0x00, 0x00, 0x14, 0x67, 0x58, 0x59, 0x5a, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x14, 0x72, 0x54, 0x52, 0x43, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x20, 0x67, 0x54, 0x52, 0x43, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x20, 0x62, 0x54, 0x52, 0x43, 0x00, 0x00, 0x02, + 0x14, 0x00, 0x00, 0x00, 0x20, 0x63, 0x68, 0x72, 0x6d, 0x00, 0x00, 0x02, + 0x34, 0x00, 0x00, 0x00, 0x24, 0x64, 0x6d, 0x6e, 0x64, 0x00, 0x00, 0x02, + 0x58, 0x00, 0x00, 0x00, 0x24, 0x64, 0x6d, 0x64, 0x64, 0x00, 0x00, 0x02, + 0x7c, 0x00, 0x00, 0x00, 0x24, 0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, + 0x53, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x47, 0x00, + 0x49, 0x00, 0x4d, 0x00, 0x50, 0x00, 0x20, 0x00, 0x62, 0x00, 0x75, 0x00, + 0x69, 0x00, 0x6c, 0x00, 0x74, 0x00, 0x2d, 0x00, 0x69, 0x00, 0x6e, 0x00, + 0x20, 0x00, 0x73, 0x00, 0x52, 0x00, 0x47, 0x00, 0x42, 0x6d, 0x6c, 0x75, + 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0c, 0x65, 0x6e, 0x55, 0x53, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x50, 0x00, 0x75, 0x00, 0x62, 0x00, 0x6c, 0x00, 0x69, 0x00, + 0x63, 0x00, 0x20, 0x00, 0x44, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x61, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x00, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, + 0x2d, 0x73, 0x66, 0x33, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0c, + 0x42, 0x00, 0x00, 0x05, 0xde, 0xff, 0xff, 0xf3, 0x25, 0x00, 0x00, 0x07, + 0x93, 0x00, 0x00, 0xfd, 0x90, 0xff, 0xff, 0xfb, 0xa1, 0xff, 0xff, 0xfd, + 0xa2, 0x00, 0x00, 0x03, 0xdc, 0x00, 0x00, 0xc0, 0x6e, 0x58, 0x59, 0x5a, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0xa0, 0x00, 0x00, 0x38, + 0xf5, 0x00, 0x00, 0x03, 0x90, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x9f, 0x00, 0x00, 0x0f, 0x84, 0x00, 0x00, 0xb6, + 0xc4, 0x58, 0x59, 0x5a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, + 0x97, 0x00, 0x00, 0xb7, 0x87, 0x00, 0x00, 0x18, 0xd9, 0x70, 0x61, 0x72, + 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x66, + 0x66, 0x00, 0x00, 0xf2, 0xa7, 0x00, 0x00, 0x0d, 0x59, 0x00, 0x00, 0x13, + 0xd0, 0x00, 0x00, 0x0a, 0x5b, 0x63, 0x68, 0x72, 0x6d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xd7, 0x00, 0x00, 0x54, + 0x7c, 0x00, 0x00, 0x4c, 0xcd, 0x00, 0x00, 0x99, 0x9a, 0x00, 0x00, 0x26, + 0x67, 0x00, 0x00, 0x0f, 0x5c, 0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, + 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x47, 0x00, + 0x49, 0x00, 0x4d, 0x00, 0x50, 0x6d, 0x6c, 0x75, 0x63, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x65, 0x6e, 0x55, + 0x53, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x73, 0x00, + 0x52, 0x00, 0x47, 0x00, 0x42, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, + 0xc2, 0x00, 0x11, 0x08, 0x02, 0x58, 0x01, 0x90, 0x03, 0x01, 0x11, 0x00, + 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00, 0x1e, 0x00, 0x01, + 0x00, 0x01, 0x04, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x05, 0x06, 0x09, 0x02, 0x03, 0x08, + 0x07, 0x0a, 0xff, 0xc4, 0x00, 0x19, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x01, 0x02, 0x05, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, + 0x02, 0x10, 0x03, 0x10, 0x00, 0x00, 0x01, 0xd9, 0x87, 0xd0, 0xc6, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xcb, + 0x81, 0x4c, 0xed, 0x2f, 0x1d, 0x27, 0x41, 0xd0, 0x53, 0x9d, 0x27, 0x03, + 0x91, 0x50, 0x77, 0x9d, 0xe7, 0x79, 0xde, 0x77, 0x75, 0xdc, 0x76, 0xb9, + 0x27, 0x1e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0xaf, 0x3d, + 0xf2, 0xdc, 0xa9, 0xf0, 0xef, 0x1e, 0xb0, 0x7f, 0x3d, 0xb0, 0x73, 0xb6, + 0x2e, 0x77, 0x1f, 0x31, 0xfe, 0x76, 0xc5, 0xc5, 0xa1, 0xdb, 0x59, 0x6f, + 0x3a, 0x47, 0x1c, 0x4e, 0x5d, 0x40, 0x38, 0x10, 0x73, 0x3b, 0x49, 0x3b, + 0x4e, 0x5c, 0x71, 0xeb, 0xa8, 0xeb, 0x39, 0x17, 0x63, 0x22, 0x72, 0xfd, + 0xd5, 0xfd, 0xcb, 0xff, 0x00, 0x57, 0xae, 0xae, 0xee, 0x5d, 0xfb, 0xcb, + 0xff, 0x00, 0x5f, 0x72, 0xf7, 0xe7, 0xd5, 0x35, 0x96, 0x49, 0xef, 0x80, + 0x00, 0x00, 0x1f, 0x23, 0x97, 0xbd, 0x37, 0x64, 0xd1, 0xe5, 0x87, 0x71, + 0x32, 0x88, 0xa1, 0xe3, 0xa4, 0xe2, 0x4b, 0x93, 0xde, 0xc9, 0xc0, 0xe1, + 0xc3, 0xbc, 0xef, 0x3b, 0xdd, 0xa9, 0x2b, 0x8a, 0xf2, 0xb8, 0xb9, 0x97, + 0x32, 0xe6, 0x5c, 0x4b, 0x99, 0x75, 0x2e, 0x45, 0xc5, 0xce, 0x6e, 0x81, + 0xd2, 0x75, 0x1d, 0x05, 0x29, 0xd0, 0x70, 0x3a, 0xce, 0x07, 0x59, 0x9e, + 0xb9, 0xb8, 0xad, 0x50, 0xfb, 0xb5, 0xa6, 0x00, 0x00, 0x5b, 0x7c, 0xf7, + 0x45, 0x98, 0xb5, 0x78, 0xa3, 0x9d, 0xc1, 0x83, 0x80, 0x0e, 0x2e, 0xc8, + 0x24, 0x80, 0x73, 0x2a, 0x4a, 0x92, 0xb0, 0xad, 0x2e, 0x05, 0x61, 0x73, + 0x2e, 0x25, 0xd0, 0xb9, 0x17, 0x42, 0xe6, 0x5c, 0x8a, 0xe2, 0xa0, 0x02, + 0x0e, 0x44, 0x02, 0x01, 0xc8, 0x10, 0x50, 0xb9, 0x98, 0x1b, 0xd7, 0xdd, + 0x96, 0xf5, 0xeb, 0x80, 0x00, 0x3c, 0x95, 0x0a, 0xe8, 0x67, 0x35, 0xfe, + 0x48, 0x41, 0x07, 0x22, 0x09, 0x00, 0x02, 0x01, 0xcc, 0xed, 0x2b, 0x0a, + 0x92, 0xb4, 0xad, 0x2b, 0xcb, 0x81, 0x70, 0x2e, 0x65, 0xd0, 0xb8, 0x97, + 0x32, 0xe8, 0x5c, 0x0a, 0xb3, 0x90, 0x04, 0x02, 0x41, 0x04, 0x82, 0x41, + 0xf3, 0xe7, 0x37, 0x1b, 0xa6, 0x3e, 0xc8, 0xbc, 0x80, 0x00, 0x6b, 0x33, + 0x2d, 0xf4, 0xe9, 0x1a, 0xe0, 0xc0, 0xe4, 0x71, 0x39, 0x1c, 0x0e, 0x44, + 0x83, 0xac, 0xe4, 0x09, 0x3b, 0x4e, 0xf2, 0xac, 0xab, 0x2b, 0x8a, 0xf2, + 0xb0, 0xb9, 0x17, 0x32, 0xe6, 0x5c, 0x8b, 0x91, 0x73, 0x2e, 0x45, 0x61, + 0xde, 0x01, 0xc8, 0xe2, 0x72, 0x38, 0x90, 0x49, 0x07, 0x20, 0x60, 0x6e, + 0x6c, 0x8e, 0xf3, 0xd9, 0x7e, 0x98, 0x00, 0x00, 0xd5, 0x7e, 0x5b, 0xea, + 0x32, 0x35, 0xc3, 0x0e, 0x27, 0x20, 0x47, 0x0e, 0xa4, 0x10, 0x40, 0x72, + 0x1d, 0x93, 0xb0, 0xee, 0x2a, 0x8a, 0xa2, 0xb8, 0xac, 0x2b, 0xca, 0xf2, + 0xe2, 0x5c, 0xcb, 0xa1, 0x72, 0x2e, 0x25, 0xc8, 0xb8, 0x95, 0x27, 0x61, + 0xc4, 0xe4, 0x70, 0x39, 0x10, 0x48, 0x00, 0x83, 0x06, 0x36, 0x07, 0x69, + 0x6d, 0x3f, 0x54, 0x00, 0x00, 0x6a, 0xb7, 0x2d, 0xf5, 0x1b, 0x1a, 0xe1, + 0xa7, 0x10, 0x49, 0xc4, 0x90, 0x09, 0x38, 0x80, 0x09, 0x3b, 0xce, 0xe2, + 0xb0, 0xab, 0x2b, 0x4a, 0xf2, 0xb4, 0xb9, 0x97, 0x12, 0xe8, 0x5c, 0x0b, + 0x91, 0x72, 0x2e, 0x45, 0x71, 0xdc, 0x40, 0x00, 0x00, 0x01, 0x26, 0x0a, + 0x6c, 0x0a, 0xd2, 0xda, 0x8e, 0xa8, 0x00, 0x00, 0xd5, 0x56, 0x5b, 0xea, + 0x42, 0x35, 0xc2, 0x81, 0x04, 0x82, 0x48, 0x0e, 0x4b, 0xa3, 0x89, 0x20, + 0x1d, 0x87, 0x79, 0x54, 0x55, 0x15, 0xa5, 0x79, 0x5a, 0x57, 0x97, 0x22, + 0xe6, 0x5c, 0x4b, 0x91, 0x72, 0x2e, 0x05, 0xc0, 0xac, 0x39, 0x90, 0x00, + 0x20, 0x00, 0x72, 0x30, 0x33, 0x60, 0x36, 0x96, 0xd5, 0x35, 0x40, 0x00, + 0x06, 0xa9, 0xf2, 0xdf, 0x52, 0x31, 0xae, 0x16, 0x00, 0x24, 0xe2, 0x49, + 0x24, 0x10, 0x00, 0x24, 0xe6, 0x76, 0x95, 0x05, 0x59, 0x56, 0x57, 0x15, + 0xc5, 0x71, 0x72, 0x2e, 0x25, 0xc8, 0xb8, 0x17, 0x12, 0xe4, 0x5c, 0x4a, + 0xf3, 0xb8, 0x00, 0x49, 0x00, 0x90, 0x0c, 0x0d, 0xcd, 0x80, 0x5a, 0x7b, + 0x57, 0xd5, 0x00, 0x00, 0x1a, 0xa5, 0xcb, 0x7d, 0x48, 0xc6, 0xb8, 0x69, + 0x07, 0x22, 0x01, 0x00, 0x12, 0x0e, 0x20, 0x1c, 0xb8, 0x75, 0xd8, 0x54, + 0x15, 0x05, 0x59, 0x58, 0x57, 0x95, 0xe5, 0x71, 0x71, 0x2e, 0x65, 0xc4, + 0xb8, 0x17, 0x22, 0xe0, 0x57, 0x95, 0xa7, 0x32, 0x40, 0x00, 0x82, 0x41, + 0x82, 0x1e, 0xfe, 0xb4, 0xb6, 0xb3, 0xaa, 0x00, 0x00, 0x35, 0x47, 0x96, + 0xfa, 0x92, 0x8d, 0x70, 0xd0, 0x49, 0x04, 0x14, 0x60, 0x82, 0x40, 0x20, + 0x02, 0x0e, 0x67, 0x69, 0xdc, 0x54, 0x95, 0x05, 0x51, 0x56, 0x55, 0x15, + 0xa5, 0x61, 0x5c, 0x56, 0x95, 0xa5, 0x59, 0x5a, 0x55, 0x1d, 0xc7, 0x22, + 0x01, 0xf4, 0x50, 0x41, 0x20, 0xc0, 0xdc, 0xf7, 0xf5, 0xa7, 0xb5, 0xbd, + 0x50, 0x00, 0x01, 0xaa, 0x1c, 0xb7, 0xd4, 0x9c, 0x6b, 0x86, 0x90, 0x72, + 0x04, 0x18, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x62, 0x44, 0x12, 0x09, 0x30, 0x13, 0xdf, 0xd6, 0x96, 0xd7, + 0x75, 0x40, 0x00, 0x06, 0xa7, 0xb2, 0xdf, 0x52, 0x91, 0xae, 0x1e, 0x41, + 0x20, 0x18, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x62, 0x24, 0x9c, 0x41, 0xc8, 0xc0, 0x0f, 0x7e, 0xda, 0x5b, + 0x60, 0xd5, 0x00, 0x00, 0x1a, 0x9c, 0xcb, 0x7d, 0x4a, 0xc6, 0xb8, 0x81, + 0xc4, 0x90, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0xb1, 0x00, 0x09, 0x06, 0x02, 0xe7, 0xbe, 0xad, 0x3d, + 0xb1, 0xea, 0x80, 0x00, 0x0d, 0x4c, 0xe5, 0xbe, 0xa5, 0xa3, 0x5c, 0x44, + 0xe2, 0x49, 0x24, 0x18, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x61, 0xe0, 0x02, 0x4c, 0x05, 0xcf, 0x7d, 0x5a, + 0x7b, 0x64, 0xd5, 0x00, 0x00, 0x1a, 0x97, 0xcb, 0x7d, 0x4b, 0xc6, 0xb8, + 0x80, 0x24, 0x82, 0x4c, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0xb0, 0xd3, 0x91, 0x07, 0x20, 0x7c, 0xfd, 0xcf, + 0x7d, 0x5a, 0x7b, 0x66, 0xd5, 0x00, 0x00, 0x1a, 0x95, 0xcb, 0x7d, 0x4b, + 0xc6, 0xb8, 0x88, 0x24, 0x10, 0x61, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x84, 0x1d, 0xa4, 0x90, 0x72, 0x3e, + 0x7c, 0x7b, 0xe6, 0xd2, 0xdb, 0x4e, 0xa8, 0x00, 0x00, 0xd4, 0x9e, 0x5b, + 0xea, 0x66, 0x35, 0xc4, 0x88, 0x00, 0x93, 0x0e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x00, 0xee, 0x3b, 0x49, + 0x24, 0xc0, 0x1c, 0xf7, 0xbd, 0xa7, 0xb6, 0xbd, 0x50, 0x00, 0x01, 0xa9, + 0x1c, 0xb7, 0xd4, 0xd4, 0x6b, 0x88, 0x80, 0x49, 0x06, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x99, 0x56, + 0x77, 0x1c, 0xce, 0x66, 0x00, 0x7b, 0xe2, 0xd2, 0xdb, 0x6e, 0xa8, 0x00, + 0x00, 0xd4, 0x7e, 0x5b, 0xea, 0x6a, 0x35, 0xc4, 0xc8, 0x04, 0x83, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7b, + 0xa8, 0xa9, 0x2a, 0x4e, 0xe3, 0x91, 0x81, 0x9e, 0xf9, 0xb4, 0xb6, 0xdf, + 0xaa, 0x00, 0x00, 0x35, 0x1b, 0x96, 0xfa, 0x9c, 0x8d, 0x71, 0x12, 0x0e, + 0x40, 0x83, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x88, 0xa8, 0x2a, 0x0e, 0xf3, 0xb0, 0xc1, 0xcf, 0x7d, + 0x5a, 0x5b, 0x71, 0xd5, 0x00, 0x00, 0x1a, 0x8b, 0xcb, 0x7d, 0x4e, 0x46, + 0xb8, 0x98, 0x00, 0x93, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7b, 0x58, 0xaa, 0x2a, 0x4e, 0xe3, 0xb4, 0xc2, + 0x9c, 0xf7, 0xf5, 0xa7, 0xb7, 0x3d, 0x50, 0x00, 0x01, 0xa8, 0xac, 0xb7, + 0xd4, 0xe4, 0x6b, 0x89, 0x80, 0x01, 0x89, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x98, 0x55, 0x95, 0x27, 0x71, + 0xd8, 0x61, 0xc6, 0xc0, 0xed, 0x2d, 0xba, 0x6a, 0x80, 0x00, 0x0d, 0x44, + 0x65, 0xbe, 0xa7, 0x63, 0x5c, 0x48, 0x92, 0x48, 0x06, 0x28, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x21, 0x52, + 0x54, 0x9d, 0xe7, 0x71, 0x88, 0x9b, 0x04, 0xb4, 0xb6, 0xef, 0xaa, 0x00, + 0x00, 0x35, 0x0d, 0x96, 0xfa, 0x9e, 0x8d, 0x71, 0x53, 0x81, 0xc8, 0x82, + 0x4c, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xeb, 0xa2, 0xa4, 0xa9, 0x3b, 0xca, 0x83, 0x16, 0x73, 0x60, 0xd6, + 0x9e, 0xde, 0x35, 0x40, 0x00, 0x06, 0xa1, 0x32, 0xdf, 0x53, 0xd1, 0xae, + 0x2a, 0x41, 0x20, 0x18, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xd5, 0xc5, 0x61, 0x54, 0x54, 0x9d, 0xa6, 0x32, + 0x6c, 0x2a, 0xd2, 0xdb, 0xd6, 0xa8, 0x00, 0x00, 0xd4, 0x16, 0x5b, 0xea, + 0x7e, 0x35, 0xc5, 0x48, 0x39, 0x10, 0x0c, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xea, 0x42, 0xb0, 0xaa, 0x2a, + 0x0a, 0x83, 0x1c, 0x36, 0x1b, 0x69, 0x6d, 0xf3, 0x54, 0x00, 0x00, 0x6a, + 0x03, 0x2d, 0xf5, 0x3f, 0x1a, 0xe2, 0xe0, 0x10, 0x0c, 0x5c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe9, 0x92, 0xb0, + 0xab, 0x2a, 0x8e, 0xf2, 0xc0, 0x6c, 0x46, 0xd2, 0xdb, 0xee, 0xa8, 0x00, + 0x00, 0xd3, 0xf6, 0x5b, 0xea, 0x82, 0x35, 0xc5, 0xc8, 0x24, 0x03, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, + 0x40, 0xac, 0x2a, 0x4a, 0xb3, 0xb8, 0xb3, 0xb9, 0xb1, 0x2b, 0x4f, 0x70, + 0x1a, 0xa0, 0x00, 0x03, 0x4f, 0x99, 0x6f, 0xaa, 0x28, 0xd7, 0x17, 0x20, + 0x90, 0x0c, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xe8, 0x42, 0xb4, 0xab, 0x2a, 0x8a, 0x92, 0xce, 0x6c, 0x62, + 0xd2, 0xdc, 0x0e, 0xa8, 0x00, 0x00, 0xd3, 0xde, 0x5b, 0xea, 0x86, 0x35, + 0xc6, 0x00, 0x24, 0x18, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xef, 0x85, 0x51, 0x59, 0xc5, 0x57, 0x55, 0x25, + 0xb4, 0xd8, 0xd5, 0xa5, 0xb8, 0x3d, 0x50, 0x00, 0x01, 0xa7, 0x9c, 0xb7, + 0xd5, 0x14, 0x6b, 0x8c, 0x12, 0x00, 0x31, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xdd, 0x0a, 0xa2, 0xa4, 0xac, + 0x2a, 0x0a, 0x17, 0x36, 0x3d, 0x69, 0xee, 0x17, 0x54, 0x00, 0x00, 0x69, + 0xe3, 0x2d, 0xf5, 0x47, 0x1a, 0xe3, 0x24, 0x1c, 0x88, 0x20, 0xc6, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x6a, + 0x2a, 0xca, 0x92, 0xa0, 0xac, 0x29, 0x4d, 0x91, 0x5a, 0x5b, 0x86, 0xd5, + 0x00, 0x00, 0x1a, 0x76, 0xcb, 0x7d, 0x52, 0x46, 0xb8, 0xc8, 0x04, 0x03, + 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7d, 0x8c, 0xa9, 0x2a, 0x8a, 0x82, 0xa7, 0x8e, 0x9e, 0xb6, 0x51, 0x69, + 0x6e, 0x1f, 0x54, 0x00, 0x00, 0x69, 0xd7, 0x2d, 0xf5, 0x49, 0x1a, 0xe3, + 0x20, 0x92, 0x01, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3e, 0xb2, 0x55, 0x95, 0x05, 0x51, 0x52, 0x70, 0x36, + 0x57, 0x69, 0x6e, 0x27, 0x54, 0x00, 0x00, 0x69, 0xcb, 0x2d, 0xf5, 0x4d, + 0x1a, 0xe3, 0x64, 0x00, 0x0c, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xf5, 0x22, 0xa4, 0xaa, 0x2a, 0x0a, 0x9e, + 0x27, 0xad, 0x96, 0xda, 0x5b, 0x8c, 0xd5, 0x00, 0x00, 0x1a, 0x71, 0xcb, + 0x7d, 0x52, 0xc6, 0xb8, 0xe0, 0x24, 0x82, 0x0c, 0x6c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf4, 0xb2, 0xa4, 0xa9, + 0x2a, 0x4a, 0x83, 0xb4, 0xd9, 0x8d, 0xa5, 0xb8, 0xcd, 0x50, 0x00, 0x01, + 0xa6, 0xfc, 0xb7, 0xd5, 0x3c, 0x6b, 0x8e, 0x10, 0x00, 0x31, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xd1, 0x0a, + 0x92, 0xa0, 0xa8, 0x2a, 0x4a, 0x83, 0x66, 0x96, 0x96, 0xe3, 0xb5, 0x40, + 0x00, 0x06, 0x9b, 0xf2, 0xdf, 0x54, 0xf1, 0xae, 0x34, 0x09, 0x20, 0x18, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x3d, 0x2a, 0x0a, 0x93, 0xbc, 0xaa, 0x2a, 0xf8, 0xd9, 0xbd, 0xe5, 0xb8, + 0xfd, 0x50, 0x00, 0x01, 0xa7, 0x5c, 0xb7, 0xd5, 0x14, 0x6b, 0x8c, 0x90, + 0x48, 0x20, 0xc7, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x19, 0xa9, 0x50, 0x54, 0x95, 0x05, 0x49, 0x5e, 0x6c, 0xf6, + 0xd2, 0xdc, 0x6e, 0xa8, 0x00, 0x00, 0xd4, 0x46, 0x6b, 0x6a, 0x3e, 0x16, + 0xc6, 0x09, 0x01, 0xc3, 0xb6, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x39, 0x19, 0x31, 0x50, 0x77, 0x9d, 0xe5, 0x51, + 0x72, 0x36, 0xa5, 0x78, 0xed, 0xf3, 0x4c, 0x40, 0x00, 0x6a, 0x7f, 0x35, + 0xb4, 0xf7, 0x0b, 0x62, 0xa0, 0x92, 0x01, 0x00, 0x00, 0x01, 0x24, 0x00, + 0x41, 0x24, 0x12, 0x40, 0x00, 0x00, 0x08, 0x24, 0x10, 0x49, 0x27, 0x61, + 0xdc, 0x77, 0x9d, 0xe5, 0x41, 0xde, 0x5e, 0x4d, 0xb5, 0x5e, 0x3b, 0x65, + 0xd3, 0x10, 0x00, 0x1a, 0xca, 0xcf, 0x5d, 0x2e, 0x67, 0xbe, 0x12, 0x43, + 0x92, 0xe8, 0x10, 0x00, 0x20, 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x09, 0x04, 0x00, 0x01, 0xcc, 0xec, 0x3b, 0x8e, 0xf3, 0xb8, 0xa8, 0x32, + 0x73, 0x71, 0xfa, 0x21, 0xb3, 0x9d, 0x12, 0x00, 0x01, 0xe2, 0x09, 0x53, + 0x42, 0x79, 0x34, 0x7c, 0xf0, 0x80, 0x01, 0x00, 0x90, 0x08, 0x24, 0x10, + 0x00, 0x00, 0x00, 0x41, 0x24, 0x02, 0x48, 0x00, 0x02, 0x09, 0x07, 0x33, + 0xb0, 0xef, 0x3b, 0x8e, 0xf3, 0x35, 0x37, 0xbf, 0xaf, 0x37, 0xb8, 0xab, + 0xe0, 0x00, 0x07, 0xc4, 0xfc, 0x77, 0xf3, 0x57, 0x8b, 0x5f, 0xcc, 0x00, + 0x00, 0x80, 0x00, 0x00, 0x00, 0x41, 0x20, 0x82, 0x40, 0x20, 0x12, 0x40, + 0x00, 0x10, 0x09, 0x20, 0x12, 0x73, 0x3b, 0x4e, 0xf3, 0xb4, 0xfa, 0x19, + 0xfa, 0x4b, 0xdb, 0x97, 0xed, 0xfe, 0xfc, 0x80, 0x00, 0xe0, 0x7e, 0x65, + 0x70, 0x6a, 0xf3, 0x1f, 0x3d, 0x74, 0x12, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x08, 0x04, 0x82, 0x09, 0x04, 0x00, 0x49, 0xd8, + 0x76, 0x95, 0x47, 0xa4, 0xbb, 0xe7, 0xf4, 0xd5, 0xbf, 0x2f, 0x20, 0x00, + 0x00, 0xd2, 0x36, 0x4b, 0xeb, 0x36, 0x55, 0xc6, 0x89, 0x04, 0x00, 0x00, + 0x00, 0x80, 0x48, 0x04, 0x00, 0x00, 0x00, 0x39, 0x0e, 0xc9, 0x00, 0x10, + 0x01, 0x24, 0x12, 0x72, 0x3b, 0x0c, 0x9c, 0xd9, 0x75, 0xa5, 0xbb, 0x7d, + 0x50, 0x00, 0x00, 0x07, 0x8d, 0x25, 0xef, 0x40, 0x19, 0x34, 0xfc, 0xe4, + 0x00, 0x01, 0x00, 0x92, 0x09, 0x00, 0x10, 0x00, 0x04, 0x90, 0x01, 0x01, + 0xc3, 0xa0, 0x41, 0x20, 0x39, 0x0e, 0x88, 0x04, 0x9c, 0xcf, 0xa5, 0x1b, + 0xfd, 0xd7, 0x9b, 0xd9, 0x35, 0xf0, 0x00, 0x00, 0x0a, 0x73, 0xf3, 0x3f, + 0x87, 0x57, 0x98, 0x7c, 0xfa, 0xa5, 0x20, 0x90, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x08, 0x00, 0x93, 0x89, 0x24, 0x12, 0x40, 0x00, 0x10, 0x09, + 0x2b, 0x4f, 0x51, 0xfa, 0xf3, 0xfa, 0x5b, 0xdd, 0x96, 0xa0, 0x00, 0x00, + 0x00, 0xd5, 0x1e, 0x7a, 0xe9, 0xf3, 0x3d, 0xf0, 0xe2, 0x09, 0x00, 0x80, + 0x00, 0x00, 0x92, 0x00, 0x20, 0x90, 0x40, 0x20, 0x12, 0x40, 0x00, 0x00, + 0x41, 0x24, 0x02, 0x4c, 0xe0, 0xdb, 0xf6, 0x88, 0xed, 0x77, 0x44, 0x40, + 0x00, 0x00, 0x07, 0xcf, 0xbc, 0xf7, 0xf3, 0x2b, 0x87, 0x57, 0xc6, 0xdd, + 0x80, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x09, 0x20, 0x10, 0x00, 0x00, + 0x00, 0x08, 0x00, 0x1c, 0x8f, 0xb4, 0xb9, 0xfa, 0x66, 0xdd, 0x97, 0xe8, + 0x7e, 0xb8, 0x00, 0x00, 0x00, 0x06, 0x91, 0xf2, 0xdf, 0x59, 0x51, 0xae, + 0x36, 0x08, 0x04, 0x80, 0x08, 0x24, 0x80, 0x00, 0x00, 0x10, 0x09, 0x20, + 0x02, 0x48, 0x00, 0x82, 0x48, 0x00, 0x19, 0x39, 0xb2, 0xdb, 0x4b, 0x78, + 0x1a, 0xa0, 0x00, 0x00, 0x00, 0x00, 0xf3, 0xcf, 0x8f, 0x5f, 0x9c, 0x0c, + 0x5a, 0xbe, 0x66, 0x08, 0x24, 0x82, 0x48, 0x00, 0x00, 0x41, 0x20, 0x10, + 0x09, 0x20, 0x82, 0x40, 0x00, 0x00, 0x40, 0x00, 0x1f, 0x50, 0x3f, 0x46, + 0x5b, 0x72, 0xfa, 0x4b, 0xdf, 0x90, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0x00, 0x63, 0xd1, 0xe0, 0x89, 0xd2, 0xcc, 0x40, 0x00, 0x10, 0x09, 0x00, + 0x10, 0x09, 0x20, 0x02, 0x09, 0x00, 0x02, 0x00, 0x00, 0x00, 0x5e, 0xcf, + 0x76, 0xd2, 0x7f, 0xa0, 0xcd, 0x99, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x78, + 0xe6, 0x5e, 0xff, 0x00, 0x3e, 0xb9, 0x34, 0xfc, 0xf4, 0x00, 0x01, 0x00, + 0x12, 0x08, 0x00, 0x00, 0x41, 0x20, 0x80, 0x48, 0x20, 0x00, 0x1c, 0x3a, + 0x07, 0xd1, 0x8d, 0xfd, 0xeb, 0xcd, 0xed, 0x3a, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xc4, 0xfc, 0xe4, 0x62, 0xd3, 0xe3, 0x5f, 0x1e, 0xed, 0xe0, + 0x92, 0x09, 0x20, 0x10, 0x48, 0x04, 0x12, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x82, 0x40, 0x20, 0xb9, 0x1e, 0xc0, 0xf7, 0xe3, 0xf4, 0x81, 0xb7, 0x37, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7, 0xfc, 0x69, 0xa2, 0x8c, 0xba, + 0x30, 0x30, 0x00, 0x00, 0x80, 0x09, 0x20, 0x02, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x41, 0x9f, 0x9b, 0xca, 0xd5, 0x9f, 0x61, 0x96, 0x98, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0xb8, 0xfc, 0xd4, 0x62, 0xd5, 0xe5, 0xcf, + 0x3e, 0xa8, 0xc8, 0x24, 0x10, 0x01, 0x24, 0x00, 0x00, 0x00, 0x02, 0x09, + 0x20, 0x92, 0x09, 0x20, 0x12, 0x41, 0x5a, 0x7a, 0x87, 0xd7, 0x9f, 0xd2, + 0xce, 0xec, 0xb5, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0xb7, 0xa1, + 0x4d, 0x22, 0x66, 0xd1, 0x84, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x24, 0x80, 0x01, 0x24, 0x12, 0x67, 0x26, 0xee, 0x34, 0xc3, 0x64, + 0x77, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x71, 0xf9, 0xa4, + 0xc3, 0xab, 0xcc, 0x7c, 0xf5, 0x4a, 0x09, 0x20, 0x00, 0x00, 0x00, 0x82, + 0x40, 0x04, 0x00, 0x49, 0x00, 0x00, 0x55, 0x1e, 0x93, 0xef, 0x9f, 0xd3, + 0x26, 0xec, 0xb7, 0x4e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, + 0x94, 0x2b, 0xa4, 0xec, 0xd7, 0xc2, 0x40, 0x04, 0x12, 0x08, 0x24, 0x02, + 0x01, 0x24, 0x12, 0x40, 0x00, 0x00, 0x00, 0x33, 0x83, 0x74, 0x3a, 0x61, + 0xb3, 0xcb, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xe3, + 0xf3, 0x41, 0x87, 0x57, 0x9a, 0xf9, 0xea, 0x94, 0x00, 0x41, 0x20, 0x82, + 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xb3, 0xd2, 0x5e, 0xbc, 0xfe, + 0x98, 0x36, 0xe5, 0xbc, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0xe2, 0x85, 0x74, 0x7f, 0x9a, 0xf8, 0x41, 0x00, 0x02, 0x48, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x70, 0x6e, 0xe7, 0x4e, 0x7d, 0x92, + 0x5e, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x78, 0xfc, + 0xd9, 0xe2, 0xd5, 0xe5, 0x6f, 0x3e, 0xad, 0xc4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x09, 0x20, 0xae, 0x3d, 0x43, 0xeb, 0xcf, 0xe9, 0x63, + 0x76, 0x5a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, + 0x4c, 0x69, 0xa2, 0x0c, 0x9a, 0x30, 0x0e, 0xa0, 0x00, 0x08, 0x04, 0x82, + 0x09, 0x20, 0x90, 0x00, 0x20, 0x90, 0x41, 0x9e, 0x1b, 0xd0, 0xd5, 0x9f, + 0x61, 0x56, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, + 0x4f, 0xce, 0x8e, 0x2d, 0x3e, 0x39, 0x9f, 0xbb, 0x27, 0x40, 0x00, 0x00, + 0x02, 0x01, 0x24, 0x00, 0x09, 0x20, 0x17, 0x33, 0xd7, 0x3e, 0xbc, 0xfe, + 0x90, 0xb7, 0x65, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3c, 0x9f, 0x3f, 0x7f, 0x9e, 0x6c, 0x5a, 0x7e, 0x6b, 0xd7, 0x00, + 0x00, 0x24, 0x82, 0x48, 0x24, 0x10, 0x00, 0x00, 0x03, 0xe8, 0x07, 0xe8, + 0x43, 0x5e, 0x6f, 0x63, 0x57, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1a, 0x14, 0xc7, 0xa3, 0x5f, 0x12, 0xa6, 0x37, 0xd0, + 0x92, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x0b, 0xd9, 0xef, 0x1a, 0x4f, + 0xf4, 0x15, 0xb3, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0xe2, 0x3e, 0x3d, 0x7e, 0x6d, 0xb1, 0x69, 0xf9, 0x4f, 0x3b, + 0x4d, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x4f, 0xa5, 0x1f, 0xa4, + 0x4d, 0xb9, 0x7d, 0x07, 0xef, 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6b, 0x37, 0x3d, 0xb4, 0xc1, 0x9a, 0xd8, 0x47, + 0x54, 0x67, 0x10, 0x00, 0x00, 0x82, 0x40, 0x07, 0x22, 0xac, 0xcc, 0x4d, + 0xbb, 0xe8, 0x86, 0xd8, 0x74, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x1e, 0x1a, 0x8d, 0x35, 0x4d, 0x9e, 0xde, + 0x7d, 0xf1, 0xea, 0x97, 0xa0, 0x1c, 0x3a, 0x71, 0x3d, 0x47, 0x11, 0xd4, + 0x81, 0xc7, 0x71, 0xf7, 0x5f, 0x7e, 0x76, 0x95, 0xa2, 0x3b, 0x05, 0xb4, + 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb0, 0xf1, 0x6c, 0xe7, 0x60, 0x00, 0x00, 0x20, 0x92, 0x01, 0x71, + 0xef, 0x32, 0x2e, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xc4, 0x00, 0x33, 0x10, 0x00, 0x01, + 0x02, 0x04, 0x03, 0x07, 0x04, 0x02, 0x02, 0x02, 0x02, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x03, 0x02, 0x04, 0x05, 0x06, 0x07, 0x08, 0x36, + 0x11, 0x13, 0x14, 0x16, 0x20, 0x35, 0x50, 0x15, 0x30, 0x34, 0x40, 0x10, + 0x12, 0x21, 0x24, 0x22, 0x25, 0x23, 0x60, 0x31, 0x41, 0x44, 0xff, 0xda, + 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x05, 0x02, 0xff, 0x00, 0xa0, 0xec, + 0x2b, 0x61, 0x45, 0xd6, 0xe1, 0x46, 0x6e, 0x54, 0x2e, 0x3e, 0x44, 0x23, + 0x55, 0xa6, 0x04, 0x6b, 0x34, 0x70, 0x8d, 0x7a, 0x84, 0x17, 0x31, 0xdb, + 0xc1, 0x73, 0x2d, 0xb8, 0x85, 0xc7, 0x6f, 0x14, 0x2b, 0xd4, 0x32, 0x85, + 0x66, 0x8e, 0x50, 0xaa, 0x53, 0x0a, 0x13, 0xf2, 0x25, 0x09, 0xa9, 0x52, + 0x83, 0xcc, 0x95, 0xfb, 0x42, 0x7f, 0x1b, 0x0f, 0xd5, 0x9c, 0x9e, 0x93, + 0xa7, 0x31, 0x57, 0xc6, 0x3b, 0x6e, 0x9f, 0x1c, 0xee, 0x3a, 0xcf, 0x44, + 0x9d, 0xc6, 0xab, 0x9e, 0x34, 0xe6, 0x30, 0xde, 0x31, 0x27, 0x31, 0x5a, + 0xf0, 0x89, 0x39, 0x89, 0xf7, 0x41, 0x4e, 0x62, 0x4d, 0x7a, 0x24, 0xe6, + 0x20, 0x54, 0x62, 0x51, 0xdf, 0x4e, 0xc4, 0xa2, 0xbb, 0xe0, 0x8d, 0x1b, + 0x9e, 0x54, 0xae, 0x64, 0x95, 0x5c, 0xc6, 0xc2, 0xe6, 0x36, 0x97, 0x31, + 0x40, 0xb9, 0x88, 0x2e, 0x62, 0x5c, 0xc6, 0xb9, 0x8c, 0xae, 0x61, 0x8c, + 0xaf, 0x5f, 0x89, 0x7a, 0xfa, 0xf5, 0xd5, 0xeb, 0x8b, 0xd7, 0xdb, 0x5c, + 0xc5, 0x2c, 0x17, 0x33, 0xc9, 0x21, 0x74, 0xc8, 0x84, 0xdd, 0xe2, 0xcc, + 0x09, 0xbb, 0xee, 0x6a, 0x14, 0xde, 0x22, 0x56, 0xa1, 0x4d, 0xe2, 0x5d, + 0xca, 0x13, 0x78, 0xa1, 0x76, 0xc2, 0xa0, 0xc5, 0x9b, 0xca, 0x05, 0x06, + 0x31, 0x5d, 0xf0, 0xa8, 0x31, 0xa2, 0xe7, 0x85, 0x4b, 0xe3, 0x85, 0x72, + 0x18, 0xa9, 0x78, 0xd5, 0x41, 0x9a, 0x54, 0xca, 0xbd, 0x32, 0xb0, 0xcf, + 0xb3, 0x78, 0x5d, 0xf4, 0xfb, 0x46, 0x9d, 0x75, 0xdf, 0x15, 0x4a, 0xf4, + 0xdc, 0xdd, 0xc0, 0xe0, 0x8a, 0x2a, 0xd3, 0xe5, 0x1a, 0x9b, 0x91, 0x23, + 0x39, 0xb5, 0x71, 0x25, 0x71, 0x51, 0x2e, 0x2d, 0xd4, 0x27, 0x66, 0xd7, + 0x1d, 0x3a, 0xb8, 0xc9, 0xa2, 0xb8, 0x97, 0xd6, 0xf9, 0xd4, 0x23, 0x89, + 0x08, 0x8a, 0x05, 0x42, 0x50, 0x50, 0xa8, 0x4a, 0x84, 0xa8, 0x4a, 0x80, + 0xa8, 0x4a, 0x84, 0xa8, 0x22, 0x2b, 0x79, 0x12, 0x0e, 0x3a, 0xb7, 0xae, + 0xad, 0xe3, 0x8b, 0x69, 0x46, 0x10, 0x51, 0x97, 0x96, 0x28, 0xc8, 0xd3, + 0xca, 0xf4, 0xca, 0x72, 0xf4, 0xba, 0x72, 0xf4, 0xa9, 0x25, 0xe9, 0x6d, + 0x05, 0xc2, 0xd4, 0x19, 0x56, 0xfd, 0xd1, 0x52, 0xa2, 0xce, 0x58, 0xd7, + 0xbc, 0x9d, 0xe1, 0x23, 0xd7, 0x39, 0x34, 0xcc, 0x8c, 0xad, 0xf7, 0x76, + 0x4c, 0x5c, 0x35, 0x7a, 0xad, 0x4c, 0xbf, 0x17, 0xb1, 0xfc, 0x7e, 0x41, + 0x41, 0x02, 0x81, 0x50, 0x95, 0x09, 0x40, 0xa8, 0x4a, 0x80, 0xa8, 0x4a, + 0x84, 0xa8, 0x4a, 0x80, 0xa8, 0x4a, 0x07, 0xf1, 0xb7, 0xa3, 0x6f, 0x5c, + 0xc3, 0x10, 0xbf, 0x05, 0x9f, 0x72, 0xcd, 0x50, 0x6a, 0xb4, 0xf9, 0xe6, + 0x2a, 0x52, 0x5d, 0x58, 0xc5, 0x55, 0x32, 0x16, 0xcd, 0xcb, 0x39, 0x18, + 0x98, 0xf7, 0x07, 0xe0, 0x20, 0x54, 0x28, 0x20, 0x54, 0x25, 0x42, 0x54, + 0x25, 0x42, 0x54, 0x05, 0x42, 0x54, 0x25, 0x03, 0xef, 0x7f, 0x94, 0xbd, + 0x6b, 0x05, 0xea, 0xd1, 0xcf, 0x5b, 0xfd, 0x58, 0xf3, 0x37, 0x17, 0x1f, + 0x71, 0x1d, 0xb5, 0x3f, 0x74, 0x20, 0x82, 0x05, 0x42, 0x54, 0x2a, 0x12, + 0xa1, 0x2a, 0x02, 0xa1, 0x2a, 0x15, 0x0a, 0x80, 0xa0, 0x50, 0x3d, 0x25, + 0x7f, 0xeb, 0xaa, 0x7b, 0xf8, 0xac, 0x60, 0x3c, 0xd7, 0xf7, 0xfa, 0xb1, + 0xeb, 0x50, 0x5c, 0x1d, 0xd3, 0xdd, 0xda, 0x81, 0x41, 0x05, 0x09, 0x40, + 0xa0, 0x54, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, 0x25, + 0x42, 0x7d, 0xda, 0x87, 0x76, 0xc0, 0x7d, 0x45, 0xd5, 0x8f, 0x5a, 0x82, + 0xe0, 0xee, 0x7d, 0x7f, 0xf8, 0xeb, 0x08, 0x15, 0x09, 0x40, 0xa8, 0x4a, + 0x84, 0xa8, 0x54, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, + 0x25, 0x0f, 0x72, 0xa1, 0xdd, 0xb0, 0x1b, 0x51, 0xf5, 0x63, 0xde, 0xa1, + 0xaf, 0xf7, 0x3f, 0x78, 0x2d, 0xaa, 0x15, 0x09, 0x41, 0x42, 0x50, 0x2a, + 0x18, 0x94, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, 0x25, 0x42, 0x54, 0x27, + 0xdc, 0xa8, 0xf7, 0x6c, 0x06, 0xd4, 0x7d, 0x58, 0xf9, 0xa8, 0x6b, 0xdd, + 0xcf, 0xdf, 0x08, 0x20, 0x81, 0x50, 0x95, 0x0a, 0x84, 0xa8, 0x4a, 0x85, + 0x42, 0x54, 0x25, 0x40, 0x54, 0x31, 0x28, 0x4a, 0x07, 0xdb, 0xa8, 0xf7, + 0x5c, 0x05, 0xd4, 0x9d, 0x58, 0xf9, 0xa8, 0xab, 0xfd, 0xcf, 0xdf, 0x08, + 0x2d, 0xa8, 0x28, 0x54, 0x25, 0x02, 0xa0, 0x2a, 0x12, 0xa1, 0x2a, 0x12, + 0xa1, 0x2a, 0x12, 0xa1, 0x2a, 0x12, 0x87, 0xb5, 0x52, 0xee, 0xb8, 0x09, + 0xa9, 0x7a, 0xb1, 0xf7, 0x51, 0xd7, 0xbb, 0x9f, 0x4f, 0x10, 0xca, 0xe2, + 0x19, 0x5c, 0x43, 0x4b, 0x88, 0x65, 0x71, 0x0c, 0xae, 0x21, 0x95, 0xc4, + 0x32, 0xb8, 0x86, 0x57, 0x10, 0xca, 0xe2, 0x19, 0x5c, 0x4b, 0x28, 0x4d, + 0x32, 0x84, 0xdc, 0xba, 0x13, 0xb2, 0xc8, 0x4f, 0xca, 0xa1, 0x51, 0x94, + 0x50, 0xd5, 0x24, 0x90, 0xab, 0x48, 0x21, 0x58, 0xa7, 0x28, 0x6b, 0x74, + 0xd0, 0xa1, 0xaf, 0x52, 0xc2, 0x17, 0x0d, 0x20, 0x28, 0x6e, 0x3a, 0x32, + 0x17, 0x35, 0x15, 0x0b, 0xa6, 0x86, 0x85, 0xd7, 0x41, 0x5c, 0xd9, 0x40, + 0x5c, 0xd9, 0x6f, 0xae, 0x6c, 0xa0, 0x2e, 0x6c, 0xa0, 0x75, 0x54, 0xbb, + 0xae, 0x02, 0x6a, 0x5e, 0xac, 0x7d, 0xd4, 0x95, 0xee, 0xe5, 0xe2, 0x2a, + 0x5d, 0xd3, 0x00, 0xf5, 0x2f, 0x56, 0x3f, 0x6a, 0x4a, 0xef, 0x72, 0xf1, + 0x15, 0x2e, 0xe9, 0x80, 0x7a, 0x9b, 0xab, 0x1f, 0xf5, 0x2d, 0x77, 0xb9, + 0x78, 0x8a, 0x97, 0x73, 0xc0, 0x2d, 0x4f, 0xd5, 0x98, 0x0d, 0x4b, 0x5d, + 0xee, 0x5e, 0x22, 0xa7, 0xdd, 0x30, 0x07, 0x53, 0xf5, 0x66, 0x03, 0x53, + 0x57, 0x3b, 0x8f, 0x88, 0xa9, 0xf7, 0x3c, 0x01, 0xd5, 0x1d, 0x59, 0x81, + 0xd4, 0xd5, 0xce, 0xe3, 0xe0, 0xc1, 0xe9, 0xa9, 0xf7, 0x4c, 0x00, 0xd5, + 0x3d, 0x59, 0x81, 0xd4, 0xf5, 0xce, 0xe3, 0xe0, 0xf6, 0xad, 0xbd, 0x15, + 0x4e, 0xe7, 0x80, 0x1a, 0xa7, 0xab, 0x30, 0x5a, 0x9e, 0xb7, 0xdc, 0x3c, + 0x18, 0x28, 0x15, 0xb7, 0xf1, 0xb5, 0x55, 0x0f, 0xfb, 0x2c, 0xbf, 0xea, + 0x9e, 0xac, 0xc1, 0x6a, 0x8a, 0xdf, 0x71, 0xf0, 0x60, 0xa0, 0x50, 0x2b, + 0x6a, 0xda, 0xaa, 0x7d, 0xcb, 0x2f, 0xda, 0xab, 0xab, 0x30, 0x7a, 0xa2, + 0xb7, 0xdc, 0x3c, 0x18, 0x28, 0x14, 0x0a, 0x05, 0x6d, 0x55, 0x2e, 0xe5, + 0x97, 0xed, 0x55, 0xd5, 0x98, 0x3d, 0x51, 0x5a, 0xee, 0x1e, 0x0e, 0x12, + 0x81, 0x5b, 0x56, 0xd4, 0x0a, 0xa8, 0xf7, 0x1c, 0xbe, 0xea, 0xae, 0xac, + 0xc2, 0x6a, 0x8a, 0xd7, 0xcf, 0xf0, 0x60, 0xa0, 0x50, 0x2b, 0x6a, 0xda, + 0xa7, 0xcf, 0xfb, 0x1c, 0xbe, 0xea, 0xae, 0xac, 0xc2, 0x6a, 0x9a, 0xd7, + 0x70, 0xf0, 0x7b, 0x50, 0x28, 0x15, 0xfb, 0x7e, 0x27, 0xbb, 0x8e, 0x5f, + 0x35, 0x5f, 0x56, 0x61, 0x75, 0x55, 0x6b, 0xb8, 0x78, 0x30, 0x50, 0x28, + 0x14, 0x0a, 0xda, 0xa7, 0x3b, 0x8e, 0x5f, 0x35, 0x5f, 0x56, 0x61, 0x75, + 0x55, 0x6b, 0xe7, 0xf8, 0x30, 0x50, 0x28, 0x14, 0x0a, 0xda, 0xa6, 0xfb, + 0x86, 0x5e, 0xf5, 0x67, 0x56, 0x61, 0xb5, 0x55, 0x67, 0xe7, 0xf8, 0x31, + 0x12, 0x05, 0x03, 0xf8, 0xda, 0xa6, 0xbb, 0x86, 0x5e, 0xf5, 0x67, 0x56, + 0x61, 0xf5, 0x5d, 0x67, 0xe7, 0xf8, 0x30, 0x54, 0x25, 0x02, 0x81, 0x5b, + 0x54, 0xc7, 0x70, 0xcb, 0xd6, 0xac, 0xea, 0xcc, 0x3e, 0xab, 0xac, 0x7c, + 0xff, 0x00, 0x07, 0x0c, 0x48, 0x15, 0x09, 0x5b, 0x50, 0x29, 0xff, 0x00, + 0x9f, 0x97, 0xad, 0x5b, 0xd5, 0x98, 0x8d, 0x57, 0x58, 0xf9, 0xde, 0x0c, + 0x15, 0x09, 0x40, 0xa0, 0x50, 0x29, 0xdf, 0x9f, 0x97, 0x9d, 0x5b, 0xd5, + 0x98, 0x8d, 0x59, 0x57, 0xf9, 0xfe, 0x0c, 0x15, 0x09, 0x40, 0xa0, 0x50, + 0x89, 0x39, 0xf3, 0xf2, 0xf3, 0xab, 0x7a, 0xb3, 0x11, 0xab, 0x2b, 0x1f, + 0x3b, 0xc1, 0x82, 0x81, 0x40, 0xa0, 0x50, 0x2a, 0x2f, 0x9d, 0x97, 0x8d, + 0x5d, 0xd5, 0x98, 0x9d, 0x59, 0x57, 0xf9, 0xde, 0x0c, 0x14, 0x0a, 0x05, + 0x02, 0x81, 0x5f, 0xfd, 0xd9, 0x78, 0xd5, 0xdd, 0x59, 0x89, 0xd5, 0xb5, + 0x7f, 0x9d, 0xe0, 0xc1, 0x40, 0xa0, 0x50, 0x28, 0x14, 0x0f, 0xf7, 0xb2, + 0xf1, 0xab, 0xfa, 0xb3, 0x15, 0xab, 0x6a, 0xdf, 0x3b, 0xc1, 0xed, 0x50, + 0x94, 0x10, 0x28, 0x15, 0x07, 0xce, 0xcb, 0xbe, 0xaf, 0xea, 0xcc, 0x5e, + 0xad, 0xaa, 0xfc, 0xdf, 0x06, 0x10, 0x40, 0xad, 0xa8, 0x14, 0xdf, 0xce, + 0xcb, 0xb6, 0xaf, 0xea, 0xcc, 0x5e, 0xad, 0xab, 0x7c, 0xdf, 0x07, 0xb5, + 0x6d, 0x40, 0xa0, 0x50, 0x29, 0xa3, 0xfd, 0xdc, 0xbb, 0x6a, 0xfe, 0xac, + 0xc5, 0xea, 0xea, 0xaf, 0xcd, 0xf0, 0x60, 0xa0, 0x50, 0x28, 0x14, 0x0a, + 0x63, 0xe6, 0xe5, 0xdb, 0x57, 0xf5, 0x66, 0x33, 0x56, 0xd5, 0x7e, 0x6f, + 0x83, 0x05, 0x02, 0x81, 0xfc, 0x02, 0xa5, 0xfe, 0x6e, 0x5d, 0x75, 0x7f, + 0x56, 0x63, 0xa1, 0xd9, 0x74, 0xd5, 0xbe, 0x67, 0x83, 0xda, 0x81, 0x40, + 0xa0, 0xb6, 0xa9, 0x43, 0xfd, 0xdc, 0xb9, 0x8d, 0xb7, 0x67, 0x56, 0x64, + 0x61, 0xd9, 0x5b, 0xab, 0xfc, 0xce, 0x9d, 0xd3, 0x8b, 0x75, 0x1a, 0xdd, + 0x38, 0xb7, 0x4e, 0x2d, 0xd3, 0x8b, 0x74, 0xe2, 0xdd, 0x46, 0xb7, 0x51, + 0xad, 0xd4, 0x6b, 0x74, 0xe2, 0xdd, 0x46, 0xb7, 0x51, 0xad, 0xd4, 0x6b, + 0x75, 0x1a, 0xdd, 0x38, 0xb7, 0x4e, 0x2d, 0xd4, 0x6b, 0x75, 0x1a, 0xdd, + 0x46, 0xb7, 0x51, 0xad, 0xd4, 0x6b, 0x75, 0x1a, 0xdd, 0x46, 0xb7, 0x51, + 0xad, 0xd4, 0x6b, 0x75, 0x1a, 0xdd, 0x46, 0xb7, 0x51, 0xad, 0xd3, 0x8b, + 0x72, 0xe7, 0x40, 0xfc, 0x49, 0x7c, 0xdc, 0xb7, 0xc1, 0xb6, 0xe0, 0xea, + 0xcc, 0xab, 0x44, 0x4d, 0xd6, 0x07, 0xf6, 0xbc, 0x10, 0x40, 0xa0, 0x81, + 0xfc, 0x02, 0xa4, 0x3f, 0x99, 0xdc, 0xb5, 0xb7, 0xb6, 0xa1, 0xd5, 0x99, + 0x56, 0x36, 0xd3, 0x2b, 0x50, 0xff, 0x00, 0x9f, 0x84, 0x1f, 0x80, 0x50, + 0x2a, 0x96, 0x36, 0xbd, 0x96, 0xa9, 0x68, 0xa1, 0x90, 0xea, 0xcc, 0x14, + 0x87, 0x17, 0x87, 0xd5, 0x81, 0xb5, 0x8f, 0x0a, 0x0f, 0xe0, 0x2a, 0x58, + 0xff, 0x00, 0x8f, 0x2f, 0x92, 0x5c, 0x36, 0x1f, 0xf5, 0x62, 0x45, 0x34, + 0xd5, 0xec, 0x49, 0xd8, 0x77, 0xd2, 0x3e, 0x1f, 0x6a, 0x92, 0x1b, 0xa9, + 0x1c, 0x36, 0xa4, 0xc5, 0x44, 0xb1, 0x3a, 0x88, 0x11, 0x0b, 0x9e, 0x8d, + 0xe8, 0x17, 0x23, 0x90, 0x16, 0xdc, 0xf0, 0xbb, 0x54, 0x10, 0x97, 0x22, + 0xb6, 0xe9, 0x1e, 0xbb, 0x71, 0x00, 0x00, 0xeb, 0xcc, 0x2d, 0x12, 0x2a, + 0x75, 0xed, 0x55, 0x6f, 0xf4, 0x99, 0xf0, 0xa1, 0x52, 0xdb, 0xfd, 0xe6, + 0x72, 0xf7, 0x41, 0xf5, 0x4b, 0xd7, 0xd8, 0xc7, 0x4b, 0x68, 0xdc, 0x16, + 0x25, 0x45, 0xbd, 0xf4, 0xaf, 0x86, 0xa6, 0xb7, 0xb8, 0x94, 0xc0, 0xbb, + 0x68, 0xdb, 0xf6, 0x27, 0xb0, 0xeb, 0x4d, 0xbe, 0xd5, 0xdd, 0x6f, 0x47, + 0x6b, 0x5c, 0xef, 0x34, 0x59, 0x77, 0xc2, 0x30, 0xd1, 0x79, 0xdb, 0x4a, + 0xde, 0x8e, 0xe9, 0xba, 0x1a, 0x69, 0xb6, 0x1a, 0xf6, 0x73, 0x23, 0x6b, + 0x2a, 0xb3, 0x5e, 0x16, 0x8e, 0xca, 0xcb, 0x75, 0xb0, 0x62, 0x3e, 0xd5, + 0xd5, 0x6f, 0xcb, 0xdd, 0x36, 0xec, 0xfc, 0x83, 0xf2, 0xce, 0x10, 0x41, + 0xf0, 0x40, 0x12, 0x64, 0xa4, 0x5f, 0x78, 0xda, 0x76, 0xfc, 0xbd, 0xab, + 0x6e, 0x7b, 0x79, 0x83, 0xb5, 0xbd, 0x1a, 0xeb, 0xa9, 0xb3, 0xfa, 0x3d, + 0xe0, 0xa9, 0x6c, 0x6f, 0x1e, 0xcb, 0xfd, 0xaf, 0xeb, 0x77, 0x7f, 0xb9, + 0x8a, 0x56, 0x97, 0x39, 0x59, 0x93, 0x2d, 0x71, 0x32, 0xde, 0x0a, 0x59, + 0xbe, 0x16, 0x57, 0x09, 0xed, 0x2e, 0x4e, 0xb2, 0xbd, 0xdc, 0x67, 0xb4, + 0xb9, 0x52, 0xf8, 0x9f, 0x67, 0x75, 0x31, 0xe0, 0x24, 0x19, 0xdf, 0x4c, + 0x60, 0xf5, 0xa7, 0xcd, 0xd7, 0xc7, 0xbd, 0x8d, 0xf6, 0x8f, 0x34, 0x59, + 0x73, 0xcd, 0xf1, 0x12, 0xde, 0x02, 0x45, 0xbe, 0x1e, 0x5b, 0x02, 0xad, + 0x13, 0x6d, 0x59, 0x7e, 0xf1, 0x00, 0x8c, 0x4d, 0xb5, 0x05, 0x9b, 0x7a, + 0x4d, 0x33, 0xb8, 0x7f, 0xef, 0x4a, 0x33, 0xbf, 0x7f, 0x0e, 0x6d, 0x5e, + 0x73, 0xbc, 0xa1, 0x84, 0x43, 0x0f, 0xbf, 0x98, 0x3b, 0x47, 0xd6, 0x6d, + 0x7a, 0x8b, 0x5b, 0xc6, 0x7e, 0xf5, 0x39, 0xad, 0xd3, 0x39, 0x79, 0xb4, + 0x4d, 0x22, 0xda, 0xfa, 0x13, 0x12, 0xec, 0xcd, 0xcb, 0xde, 0xb6, 0xbb, + 0xd6, 0x7d, 0xcf, 0x30, 0xd6, 0xe5, 0xef, 0xb9, 0x2e, 0xd6, 0xfd, 0xeb, + 0x32, 0xd7, 0x7a, 0xf1, 0xba, 0x25, 0xa5, 0x98, 0x93, 0x96, 0xfa, 0x39, + 0x88, 0xb3, 0xbd, 0x4a, 0x8b, 0x52, 0x67, 0xf7, 0x6f, 0xee, 0x53, 0x59, + 0xfd, 0x1b, 0xcb, 0xad, 0x9f, 0xe9, 0xd4, 0x3f, 0xa5, 0x3b, 0x27, 0x2f, + 0x50, 0x93, 0xbc, 0x6d, 0x97, 0xad, 0x2b, 0x91, 0xe6, 0x8b, 0x2e, 0xfd, + 0xa6, 0x5a, 0x2f, 0x3b, 0x69, 0xdb, 0x6f, 0xdd, 0x97, 0x1c, 0x94, 0x9c, + 0xb5, 0x3a, 0x4f, 0xe9, 0xe6, 0x2a, 0xce, 0xe3, 0xe9, 0x35, 0x26, 0x7f, + 0x76, 0xfe, 0xd5, 0x35, 0x9f, 0xd1, 0xbc, 0xb9, 0x59, 0xbc, 0x2d, 0x3f, + 0xea, 0x4f, 0xc8, 0xcb, 0x54, 0xe4, 0x6e, 0xeb, 0x6a, 0x66, 0xd3, 0xb8, + 0x5f, 0x68, 0xb2, 0xef, 0xd8, 0x65, 0xa2, 0xf3, 0xb6, 0x95, 0xb3, 0x33, + 0x77, 0x5c, 0x54, 0xf9, 0x09, 0x5a, 0x5c, 0x8f, 0xd5, 0xcc, 0x2d, 0x95, + 0xea, 0x94, 0x6a, 0x8b, 0x3f, 0xbc, 0x1f, 0x62, 0x9c, 0xce, 0xed, 0xbc, + 0xbb, 0x59, 0x66, 0x99, 0x45, 0xfa, 0xd3, 0x32, 0xcc, 0x4e, 0x4b, 0xdf, + 0xd6, 0xa3, 0xd6, 0x6d, 0xd1, 0x32, 0xc9, 0x65, 0xcf, 0xad, 0x2e, 0xc9, + 0x7d, 0xdb, 0x22, 0xd6, 0x7a, 0xf2, 0xba, 0x25, 0x65, 0x98, 0x92, 0x96, + 0xfa, 0xf8, 0xf7, 0x65, 0x7a, 0xfd, 0xb7, 0x3a, 0xce, 0xf5, 0xa3, 0xfc, + 0x1f, 0xab, 0x22, 0xd6, 0xe5, 0x9c, 0xbe, 0x59, 0x5e, 0x89, 0x6e, 0xfd, + 0x87, 0x1b, 0x81, 0xd8, 0x31, 0x3e, 0xcc, 0x72, 0xca, 0xba, 0xe7, 0x58, + 0xdd, 0x39, 0xf5, 0x25, 0x18, 0xdf, 0xbd, 0x87, 0x36, 0x6b, 0xb7, 0xcd, + 0xd8, 0xd3, 0x4d, 0xb0, 0xd7, 0xd9, 0xc6, 0x1b, 0x24, 0x5e, 0x36, 0xac, + 0xd3, 0x26, 0x38, 0x22, 0x1f, 0xa9, 0xfa, 0x72, 0xad, 0x70, 0xcc, 0x60, + 0x9d, 0x8d, 0xc9, 0xd6, 0x97, 0xdb, 0xc6, 0xeb, 0x24, 0xda, 0xd7, 0x44, + 0xf3, 0x1f, 0xac, 0x5f, 0x4a, 0x45, 0x9d, 0xeb, 0xb8, 0x2f, 0x65, 0x9b, + 0xc6, 0xf0, 0xfb, 0x98, 0x83, 0x68, 0x31, 0x7a, 0xdb, 0x15, 0x09, 0x17, + 0xa5, 0x9e, 0x75, 0xb2, 0xdc, 0x5f, 0x42, 0x18, 0x4c, 0x71, 0x4a, 0xcb, + 0x46, 0xb0, 0xca, 0xcb, 0x6a, 0xc6, 0xb4, 0xfe, 0xee, 0x36, 0x61, 0x49, + 0xaa, 0xc3, 0x33, 0x2a, 0x1d, 0x4e, 0x4b, 0xb8, 0xd1, 0xd8, 0x7d, 0xdd, + 0x85, 0x36, 0xc3, 0xae, 0x29, 0x79, 0x68, 0x25, 0x86, 0x04, 0xe1, 0x5c, + 0xc3, 0x0f, 0xfd, 0xfc, 0x42, 0xc1, 0x2a, 0x2d, 0xd6, 0xae, 0x4c, 0x2e, + 0xbd, 0x6d, 0x88, 0x9c, 0x93, 0x30, 0x1e, 0x1d, 0xb5, 0xc3, 0xb6, 0xb8, + 0x76, 0xd7, 0x0e, 0xda, 0xdc, 0x36, 0xb8, 0x76, 0xd7, 0x0e, 0xda, 0xe1, + 0xdb, 0x5c, 0x3b, 0x6b, 0x70, 0xda, 0xdc, 0x36, 0xb8, 0x76, 0xd4, 0x12, + 0xc0, 0x9a, 0x06, 0x1a, 0xde, 0xf7, 0x23, 0xb6, 0x06, 0x02, 0x51, 0xed, + 0xb9, 0x8f, 0x04, 0xfd, 0x2e, 0x99, 0x34, 0xb9, 0x76, 0xdf, 0x5c, 0xbb, + 0x6f, 0xae, 0x5d, 0xb7, 0xd7, 0x2e, 0xdb, 0xeb, 0x97, 0x6d, 0xf5, 0xcb, + 0xb6, 0xfa, 0xe5, 0xdb, 0x7d, 0x72, 0xed, 0xbe, 0xb9, 0x72, 0xde, 0x5c, + 0xbb, 0x6f, 0xae, 0x5c, 0xb7, 0x97, 0x2e, 0x5b, 0xca, 0x5e, 0x91, 0x49, + 0x94, 0x8f, 0xfe, 0x89, 0xff, 0xc4, 0x00, 0x31, 0x11, 0x00, 0x01, 0x01, + 0x05, 0x06, 0x04, 0x06, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x03, 0x02, 0x11, 0x31, 0x50, 0x71, 0x00, 0x20, 0x40, 0x51, + 0x91, 0xd1, 0x12, 0x21, 0x30, 0x32, 0x41, 0x52, 0x61, 0x81, 0xb1, 0xc1, + 0x13, 0xa1, 0x42, 0x60, 0x22, 0xf0, 0xf1, 0xff, 0xda, 0x00, 0x08, 0x01, + 0x03, 0x01, 0x01, 0x3f, 0x01, 0xfe, 0x84, 0xe3, 0x67, 0x1c, 0x8e, 0x96, + 0x71, 0xc8, 0xe9, 0x67, 0x1c, 0x8e, 0x96, 0xe1, 0x6b, 0x23, 0xa1, 0xb7, + 0x0b, 0x5e, 0x53, 0xa1, 0xb7, 0x0b, 0x5e, 0x53, 0xa1, 0xb7, 0x0b, 0x59, + 0x1d, 0x0d, 0xb8, 0x5a, 0xf2, 0x9d, 0x0d, 0xb8, 0x5a, 0xf2, 0x9d, 0x0d, + 0xb8, 0x5a, 0xf2, 0x9d, 0x0d, 0xb8, 0x5a, 0xf2, 0x9d, 0x0d, 0xb8, 0x5a, + 0xc8, 0xe8, 0x6c, 0xe3, 0x91, 0xd2, 0xce, 0x39, 0x1d, 0x2c, 0xe3, 0x91, + 0xd2, 0xce, 0x39, 0x1d, 0x2c, 0xe3, 0x96, 0x18, 0x02, 0x60, 0x1f, 0x60, + 0x91, 0xf1, 0x36, 0xfc, 0x4c, 0xfa, 0xdb, 0xf1, 0xb1, 0x97, 0xec, 0xdb, + 0x81, 0x9c, 0xad, 0xc2, 0xce, 0x42, 0xdc, 0x2c, 0xf9, 0x46, 0x82, 0xce, + 0x19, 0x0c, 0x43, 0x86, 0x42, 0xdc, 0x23, 0x21, 0xa5, 0xb8, 0x59, 0xf2, + 0x8d, 0x2d, 0xc0, 0xce, 0x42, 0xdc, 0x0c, 0xe5, 0x6f, 0xc6, 0xce, 0x5f, + 0xb3, 0x6f, 0xc6, 0xcf, 0xae, 0xb6, 0x29, 0x64, 0x75, 0xb1, 0x64, 0xb3, + 0x1e, 0x93, 0x0c, 0x71, 0x53, 0xe6, 0xc0, 0x01, 0x09, 0x43, 0x6c, 0x3b, + 0x98, 0x87, 0xc7, 0x40, 0x07, 0x97, 0x58, 0x07, 0x07, 0x4a, 0x63, 0x62, + 0x1c, 0x48, 0xbe, 0x90, 0xe6, 0x4c, 0xad, 0x58, 0x83, 0xe9, 0xf1, 0xff, + 0x00, 0x6f, 0xa5, 0x03, 0x59, 0x5a, 0xb0, 0x15, 0xbe, 0x94, 0x0d, 0x65, + 0x6a, 0xf6, 0x8a, 0xfd, 0x1b, 0xe9, 0x40, 0xd6, 0x56, 0xaf, 0x68, 0xaf, + 0xd1, 0xbe, 0x94, 0x0d, 0x65, 0x6a, 0xf6, 0x8a, 0xef, 0x7d, 0x28, 0x1a, + 0xca, 0xd5, 0xed, 0x15, 0xde, 0xfa, 0x50, 0x35, 0x95, 0xab, 0xda, 0x2b, + 0xbd, 0xf4, 0xa0, 0x6b, 0x2b, 0x57, 0xb4, 0x57, 0xe8, 0xdf, 0x4b, 0xb4, + 0xd7, 0x69, 0x5a, 0xbd, 0xa2, 0xbb, 0xdf, 0x4a, 0x06, 0xb2, 0xb5, 0x60, + 0x2b, 0xbd, 0xf4, 0xa0, 0x6b, 0x2b, 0x57, 0xb7, 0xdf, 0xe8, 0xdf, 0x4b, + 0xb4, 0xd7, 0x69, 0x5a, 0xbd, 0xa2, 0xbb, 0xdf, 0x4a, 0x06, 0xb2, 0xb5, + 0x60, 0x2b, 0x7d, 0x28, 0x1a, 0xca, 0xd5, 0x80, 0xae, 0xf7, 0xd2, 0x81, + 0xae, 0xd2, 0xb5, 0x60, 0x2b, 0xbd, 0xf4, 0xa0, 0x6b, 0x2b, 0x57, 0xb4, + 0x57, 0x7b, 0xe9, 0x40, 0xd6, 0x56, 0xaf, 0x68, 0xae, 0xf7, 0xd2, 0x81, + 0xac, 0xad, 0x5e, 0xd1, 0x5d, 0xef, 0xa5, 0x03, 0x59, 0x5a, 0xb0, 0x15, + 0xde, 0xfa, 0x50, 0x35, 0x95, 0xab, 0x01, 0x5b, 0xe9, 0x40, 0xd6, 0x56, + 0xac, 0x05, 0x6f, 0xa5, 0x03, 0x59, 0x5a, 0xb0, 0x15, 0xbe, 0x94, 0x0d, + 0x65, 0x6a, 0xc0, 0x56, 0xfa, 0x50, 0x35, 0x95, 0xab, 0x01, 0x5b, 0xe9, + 0x40, 0xd6, 0x56, 0xac, 0x05, 0x6f, 0xa5, 0x03, 0x59, 0x5a, 0xb0, 0x15, + 0xbe, 0x94, 0x0d, 0x65, 0x6a, 0xf6, 0x8a, 0xef, 0x7d, 0x28, 0x1a, 0xca, + 0xd5, 0x80, 0xad, 0xf4, 0xa0, 0x6b, 0x2b, 0x57, 0xb4, 0x57, 0x7b, 0xe9, + 0x40, 0xd6, 0x56, 0xac, 0x05, 0x6f, 0xa5, 0x03, 0x59, 0x5a, 0xbd, 0xa2, + 0xbb, 0xdf, 0x4b, 0xb4, 0xd7, 0x69, 0x5a, 0xbd, 0xa2, 0xbb, 0xdf, 0x4b, + 0xb4, 0xd7, 0x69, 0x5a, 0xbd, 0xa2, 0xbb, 0xdf, 0x4a, 0x06, 0xb2, 0xb5, + 0x7b, 0x45, 0x7e, 0x8d, 0xf4, 0xa0, 0x6b, 0x2b, 0x57, 0xb4, 0x57, 0x7b, + 0xe9, 0x40, 0xd7, 0xea, 0x56, 0xaf, 0x68, 0xae, 0xf7, 0xd2, 0x81, 0xac, + 0xad, 0x58, 0x0a, 0xdf, 0x4a, 0x06, 0xb2, 0xb5, 0x60, 0x2b, 0x7d, 0x2f, + 0x1f, 0x6f, 0xb9, 0x5a, 0xbe, 0x1e, 0xf7, 0xd2, 0xf1, 0xf6, 0x95, 0xab, + 0xe1, 0xef, 0x7d, 0x3e, 0xef, 0x69, 0x5a, 0x9d, 0xd7, 0xd9, 0xe4, 0xd0, + 0xac, 0xad, 0xa2, 0xf6, 0x8d, 0x7a, 0x00, 0xbc, 0x03, 0xe9, 0x29, 0x3c, + 0x81, 0x3e, 0x9d, 0x14, 0xcf, 0xf8, 0xbb, 0x29, 0x4a, 0x87, 0x93, 0xb3, + 0xe8, 0xa6, 0x5c, 0xd5, 0x79, 0x4a, 0x54, 0x2f, 0x6a, 0x9c, 0xba, 0x4c, + 0x97, 0x80, 0x64, 0xed, 0x17, 0x02, 0x7a, 0x69, 0x18, 0x8f, 0x79, 0x3a, + 0xa6, 0x03, 0xdf, 0xa6, 0x0b, 0x8b, 0xe4, 0xe4, 0xbc, 0x93, 0xd4, 0x4c, + 0xf2, 0x76, 0x52, 0x55, 0x0b, 0x83, 0xb3, 0xf8, 0xea, 0xb2, 0x78, 0x4b, + 0xf5, 0x92, 0xb6, 0x5e, 0xd7, 0x59, 0x32, 0xf6, 0x69, 0xca, 0x46, 0xd9, + 0x73, 0x35, 0xe5, 0xd7, 0x60, 0xb9, 0xaa, 0xf2, 0x91, 0xa8, 0x5e, 0xd5, + 0x39, 0x60, 0x18, 0x3c, 0x43, 0xe6, 0x42, 0xd9, 0x70, 0xc0, 0xa6, 0x5c, + 0x5d, 0x9f, 0xcc, 0x85, 0x42, 0xf2, 0xec, 0xbe, 0x70, 0x4c, 0x97, 0x80, + 0x71, 0xed, 0x1e, 0x10, 0xfc, 0x1a, 0x67, 0x9b, 0xb3, 0xc7, 0xa8, 0x79, + 0xbb, 0x2f, 0x9c, 0x23, 0x25, 0xe0, 0x1c, 0x69, 0x2e, 0x04, 0xe1, 0x53, + 0x3c, 0xdd, 0x9e, 0x35, 0x46, 0xb9, 0xf0, 0xe5, 0x86, 0x05, 0xe0, 0x1c, + 0x5b, 0x45, 0xc0, 0x9c, 0x3a, 0x67, 0x9b, 0xb3, 0xf9, 0xc5, 0xa8, 0xd3, + 0xcb, 0xb2, 0xf9, 0xc4, 0x32, 0x5e, 0x1f, 0x89, 0x68, 0xb8, 0x13, 0xa5, + 0x71, 0x29, 0x97, 0x17, 0x78, 0x1f, 0x9f, 0xf7, 0x96, 0x25, 0x46, 0x9e, + 0x5d, 0x96, 0x29, 0x93, 0xc4, 0x30, 0xed, 0x1e, 0x11, 0xf1, 0x8b, 0x61, + 0xa7, 0x1f, 0x43, 0x87, 0x6d, 0xae, 0x23, 0xe8, 0x39, 0x63, 0x18, 0x69, + 0xe3, 0xd4, 0x61, 0x5b, 0x69, 0xc3, 0xd4, 0xe3, 0x59, 0x3c, 0x27, 0xd3, + 0xc7, 0x0a, 0xd1, 0xe2, 0x2f, 0xd2, 0x98, 0xe4, 0xda, 0xfe, 0x27, 0xdb, + 0x6d, 0xb0, 0x6a, 0x37, 0xfc, 0x47, 0xbe, 0xd2, 0x06, 0x54, 0x74, 0x79, + 0x8f, 0xdd, 0x83, 0x40, 0xc0, 0xf5, 0xcb, 0x4c, 0x88, 0x9b, 0x34, 0xa1, + 0x3c, 0x87, 0x21, 0xfb, 0x91, 0xbc, 0xe7, 0x67, 0x9c, 0xce, 0xb6, 0x79, + 0xcc, 0xeb, 0x67, 0x9c, 0xce, 0xb6, 0x79, 0xcc, 0xeb, 0x67, 0x9c, 0xce, + 0xb6, 0x79, 0xcc, 0xeb, 0x67, 0x9c, 0xce, 0xb6, 0x79, 0xcc, 0xeb, 0x67, + 0x9c, 0xce, 0xb6, 0x79, 0xcc, 0xeb, 0x67, 0x9c, 0xce, 0xb6, 0x79, 0xcc, + 0xeb, 0x67, 0x9c, 0xcf, 0xf4, 0x5f, 0xff, 0xc4, 0x00, 0x33, 0x11, 0x00, + 0x01, 0x01, 0x04, 0x06, 0x09, 0x03, 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x12, 0x32, 0xc1, 0x00, 0x11, 0x20, + 0x50, 0x72, 0x91, 0x21, 0x31, 0x40, 0x41, 0x51, 0x52, 0x71, 0xb1, 0xd1, + 0x30, 0x61, 0x81, 0x13, 0xa1, 0xe1, 0xf0, 0x22, 0x42, 0xf1, 0x60, 0xff, + 0xda, 0x00, 0x08, 0x01, 0x02, 0x01, 0x01, 0x3f, 0x01, 0xff, 0x00, 0x82, + 0xac, 0x52, 0xb1, 0xc4, 0x67, 0x47, 0x93, 0xcc, 0x33, 0x14, 0x79, 0x3c, + 0xc3, 0x31, 0x47, 0x93, 0xcc, 0x33, 0x14, 0x79, 0x3c, 0xc9, 0xcc, 0x51, + 0xf4, 0xf3, 0x27, 0x31, 0x47, 0xd3, 0xcc, 0x9c, 0xc5, 0x1f, 0x4f, 0x32, + 0x73, 0x14, 0x7d, 0x3c, 0xc9, 0xcc, 0x51, 0xe4, 0xf3, 0x27, 0x31, 0x47, + 0x93, 0xcc, 0x9c, 0xc5, 0x1e, 0x4f, 0x32, 0x73, 0x14, 0x79, 0x3c, 0xc3, + 0x31, 0x47, 0x93, 0xcc, 0x33, 0x14, 0x78, 0x71, 0x19, 0xd2, 0xb1, 0xc4, + 0x67, 0xb3, 0x95, 0x04, 0xeb, 0x35, 0x50, 0xb7, 0x1b, 0x85, 0x7d, 0x74, + 0x79, 0xa7, 0xd6, 0x57, 0xb0, 0xa7, 0xd5, 0x5f, 0x1f, 0xb0, 0xf1, 0x4f, + 0xa8, 0xbe, 0x6e, 0xd4, 0x7d, 0x7c, 0xc6, 0x8f, 0xab, 0x98, 0xe6, 0x68, + 0xf2, 0xb9, 0x8e, 0x66, 0x95, 0x9e, 0x3b, 0x3d, 0x67, 0x89, 0xce, 0x8f, + 0x2b, 0x98, 0xe6, 0x68, 0xfa, 0xf9, 0x95, 0x9d, 0x3e, 0xa2, 0xf9, 0x8d, + 0x3e, 0xa2, 0xf9, 0xbb, 0x78, 0xa7, 0xd5, 0x5f, 0x1f, 0xb0, 0xf1, 0x4f, + 0xac, 0xbf, 0x6c, 0xa8, 0x1b, 0xf1, 0x4e, 0x5e, 0x3f, 0x34, 0x4a, 0xd2, + 0xad, 0x47, 0xe3, 0x7f, 0xa4, 0xd1, 0xa3, 0xba, 0x06, 0xbe, 0xd4, 0x24, + 0x9d, 0x26, 0xe8, 0x66, 0xd1, 0xed, 0x07, 0x5f, 0x7f, 0xcf, 0xa0, 0xa2, + 0xe8, 0x27, 0x85, 0x09, 0xac, 0xd6, 0x77, 0xdd, 0x3a, 0xbe, 0x28, 0x92, + 0xf0, 0x06, 0xdb, 0x73, 0xa0, 0x0e, 0x27, 0xb7, 0xfb, 0x75, 0xb0, 0x3a, + 0x08, 0xf7, 0xaf, 0x3f, 0xf2, 0xdb, 0x78, 0x87, 0x4f, 0xde, 0xd7, 0x5b, + 0x0d, 0x67, 0xa5, 0xb6, 0xf1, 0x0c, 0x33, 0x37, 0x5b, 0x08, 0x8f, 0x49, + 0x8b, 0x6d, 0xe2, 0x18, 0x66, 0x6e, 0xb6, 0x11, 0x1c, 0x33, 0x16, 0xdb, + 0xc4, 0x30, 0xcc, 0xdd, 0x6c, 0x62, 0x38, 0x66, 0x2d, 0xb7, 0x88, 0x61, + 0x99, 0xba, 0xd8, 0x44, 0x70, 0xcc, 0x5b, 0x6f, 0x10, 0xc3, 0x33, 0x75, + 0xb0, 0x88, 0xe1, 0x98, 0xb6, 0xde, 0x21, 0x86, 0x66, 0xeb, 0x61, 0x11, + 0xc3, 0x31, 0x6d, 0xbc, 0x43, 0x0c, 0xcd, 0xd6, 0xc2, 0x23, 0xd2, 0x62, + 0xdb, 0x78, 0x86, 0x19, 0x9b, 0xad, 0x84, 0x47, 0xa4, 0xc5, 0xb6, 0xf1, + 0x0c, 0x33, 0x37, 0x5b, 0x08, 0x8e, 0x19, 0x8b, 0x6d, 0xe2, 0x18, 0x66, + 0x6e, 0xb6, 0x11, 0x1c, 0x33, 0x16, 0xdb, 0xc4, 0x30, 0xcc, 0xdd, 0x6c, + 0x22, 0x3d, 0x26, 0x2d, 0xb7, 0x88, 0x61, 0x99, 0xba, 0xd8, 0x44, 0x70, + 0xcc, 0x5b, 0x6f, 0x10, 0xc3, 0x33, 0x75, 0xb0, 0x88, 0xe1, 0x98, 0xb6, + 0xde, 0x21, 0x86, 0x66, 0xeb, 0x61, 0x11, 0xc3, 0x31, 0x6d, 0xbc, 0x43, + 0x0c, 0xcd, 0xd6, 0xc2, 0x23, 0x86, 0x62, 0xdb, 0x78, 0x86, 0x19, 0x9b, + 0xad, 0x84, 0x47, 0x0c, 0xc5, 0xb6, 0xf1, 0x0c, 0x33, 0x37, 0x5b, 0x08, + 0x8e, 0x19, 0x8b, 0x6d, 0xe2, 0x18, 0x66, 0x6e, 0xb6, 0x11, 0x1e, 0x93, + 0x16, 0xdb, 0xc4, 0x30, 0xcc, 0xdd, 0x6c, 0x22, 0x3d, 0x26, 0x2d, 0xb7, + 0x88, 0x61, 0x99, 0xba, 0xd8, 0x44, 0x70, 0xcc, 0x5b, 0x6f, 0x10, 0xc3, + 0x33, 0x75, 0xb0, 0x88, 0xe1, 0x98, 0xb6, 0xde, 0x21, 0x86, 0x66, 0xeb, + 0x61, 0x11, 0xc3, 0x31, 0x6d, 0xbc, 0x43, 0x0c, 0xcd, 0xd6, 0xc2, 0x23, + 0x86, 0x62, 0xdb, 0x78, 0x86, 0x19, 0x9b, 0xad, 0x84, 0x47, 0x0c, 0xc5, + 0xb6, 0xf1, 0x0c, 0x33, 0x37, 0x5b, 0x08, 0x8e, 0x19, 0x8b, 0x6d, 0xe2, + 0x18, 0x66, 0x6e, 0xb6, 0x11, 0x1c, 0x33, 0x16, 0xdb, 0xc4, 0x30, 0xcc, + 0xdd, 0x6c, 0x22, 0x38, 0x66, 0x2d, 0xb7, 0x88, 0x61, 0x99, 0xba, 0xd8, + 0x44, 0x70, 0xcc, 0x5b, 0x6f, 0x10, 0xc3, 0x33, 0x75, 0xb0, 0x88, 0xe1, + 0x98, 0xb6, 0xde, 0x21, 0x86, 0x66, 0xeb, 0x61, 0x11, 0xc3, 0x31, 0x6d, + 0xbc, 0x43, 0x0c, 0xcd, 0xd6, 0xc2, 0x23, 0x86, 0x62, 0xdb, 0x78, 0x86, + 0x19, 0x9b, 0xad, 0x84, 0x47, 0x0c, 0xc5, 0xb6, 0xf1, 0x0c, 0x33, 0x37, + 0x5b, 0x08, 0x8e, 0x19, 0x8b, 0x6d, 0xe2, 0x18, 0x66, 0x6e, 0xb6, 0x11, + 0x1c, 0x33, 0x16, 0xdb, 0xc4, 0x3a, 0x4c, 0xdd, 0x6c, 0x22, 0x3d, 0x26, + 0x2d, 0xb7, 0xd6, 0x9e, 0x97, 0x5b, 0x0d, 0x67, 0xa5, 0xb6, 0xff, 0x00, + 0xd7, 0xe6, 0x57, 0x5b, 0x0f, 0xed, 0xf1, 0x3b, 0x6d, 0xf5, 0x27, 0xe6, + 0xeb, 0x61, 0xfd, 0xbe, 0x3f, 0x7e, 0xf6, 0xdb, 0x0f, 0xe1, 0xd0, 0x8f, + 0x17, 0x5b, 0x18, 0x3a, 0x93, 0xe2, 0x56, 0xd6, 0x2b, 0x42, 0xba, 0x76, + 0xd3, 0x75, 0xa0, 0x54, 0x94, 0x8f, 0x6e, 0xfa, 0x7d, 0x05, 0x0a, 0x94, + 0x47, 0x03, 0x74, 0xa4, 0x56, 0x40, 0xe2, 0x47, 0xa2, 0xd8, 0x54, 0xaa, + 0xf8, 0x8e, 0xdf, 0xa2, 0xe9, 0x62, 0x3f, 0x91, 0x3c, 0x07, 0x7f, 0xd3, + 0xe8, 0xb5, 0x4d, 0x69, 0xc3, 0xa7, 0xcf, 0xda, 0xe9, 0x64, 0x2a, 0x40, + 0xf7, 0xd3, 0xe3, 0xed, 0xe9, 0x28, 0x3a, 0xa2, 0x3f, 0x6a, 0xdd, 0x73, + 0xa4, 0x3c, 0xa0, 0x3f, 0x7d, 0xfd, 0x36, 0xc9, 0xd4, 0xaf, 0x83, 0x2b, + 0x9d, 0x82, 0x75, 0xab, 0xe0, 0x7a, 0x6a, 0x0f, 0x02, 0x38, 0xd0, 0xe8, + 0xf8, 0xb9, 0x75, 0xfc, 0xd1, 0x21, 0xd0, 0x07, 0x0f, 0x51, 0xb2, 0x6a, + 0x55, 0x7b, 0x8f, 0x7b, 0x95, 0x8a, 0x6b, 0x55, 0x7c, 0x3b, 0xfa, 0xab, + 0x4b, 0xc9, 0x23, 0x7e, 0xb1, 0xd7, 0xf7, 0x45, 0xca, 0xcd, 0x2e, 0xa4, + 0x71, 0xd6, 0x7d, 0x66, 0xa9, 0x75, 0x5e, 0xc7, 0x4f, 0x9b, 0x8d, 0x92, + 0x5e, 0x57, 0xb0, 0xd2, 0x65, 0xeb, 0xb5, 0x4b, 0xc9, 0xf7, 0x1a, 0x7c, + 0xdc, 0x6c, 0x93, 0x52, 0x7d, 0xce, 0x9f, 0x1b, 0x02, 0xd2, 0xea, 0x88, + 0xdd, 0xac, 0x74, 0xfd, 0xd1, 0x70, 0xa1, 0x2f, 0x28, 0x0c, 0xf6, 0x16, + 0xc9, 0xad, 0x35, 0xf0, 0xed, 0x70, 0xb1, 0x4d, 0x49, 0x7b, 0x7a, 0xbb, + 0x6c, 0x4a, 0x4b, 0xaa, 0x23, 0x2e, 0x9b, 0xb6, 0xf4, 0xa5, 0xe5, 0x01, + 0x9f, 0x4d, 0x8d, 0xb2, 0x6b, 0x0f, 0x70, 0xd7, 0xd3, 0xf1, 0xb7, 0xb1, + 0x4d, 0x41, 0xed, 0xe7, 0xb7, 0xfb, 0xb1, 0xeb, 0xa2, 0x83, 0xaa, 0x23, + 0x86, 0xda, 0x90, 0xf2, 0x80, 0xfd, 0xaa, 0x9a, 0xb4, 0x6c, 0x8d, 0x93, + 0xa1, 0xee, 0x1a, 0xfa, 0x6d, 0xac, 0x53, 0xa1, 0xee, 0x3a, 0x07, 0x4d, + 0x94, 0x8a, 0xc5, 0x47, 0x7d, 0x14, 0x97, 0x49, 0x1c, 0x3f, 0x46, 0xd6, + 0x90, 0xf1, 0x02, 0x9a, 0xb4, 0x6c, 0xcd, 0x93, 0xa1, 0xee, 0x1a, 0xfa, + 0x7e, 0x36, 0xb6, 0x29, 0xa8, 0x3d, 0xc7, 0xb7, 0xe7, 0xc6, 0xd0, 0xa4, + 0xba, 0xa2, 0x9c, 0xba, 0x6e, 0xda, 0x50, 0x97, 0x94, 0x06, 0x7d, 0x36, + 0x96, 0xc9, 0xac, 0x57, 0xbd, 0x3d, 0xb6, 0x96, 0x29, 0xa8, 0x57, 0xbc, + 0xf6, 0xda, 0x96, 0x97, 0x55, 0x56, 0xed, 0xdd, 0x3f, 0x1b, 0x3a, 0x12, + 0xf2, 0xaa, 0xdd, 0xbf, 0xa6, 0xd6, 0xd5, 0x2f, 0x27, 0xdc, 0x69, 0x13, + 0x1b, 0x3b, 0x24, 0xba, 0x9f, 0x73, 0xa4, 0xf8, 0xdb, 0x1a, 0x25, 0xd5, + 0x7b, 0x1d, 0x22, 0x7b, 0x2b, 0x24, 0xbc, 0xaf, 0x61, 0xa7, 0xc0, 0xdb, + 0x56, 0x97, 0x93, 0x56, 0xfd, 0xdd, 0x76, 0x54, 0x25, 0xd4, 0xd5, 0xbf, + 0x7f, 0x5d, 0xb9, 0xab, 0x3f, 0xec, 0x3e, 0x44, 0xfc, 0xe7, 0xb1, 0xb2, + 0x67, 0xfd, 0x8f, 0xc7, 0x9f, 0x17, 0x02, 0xd9, 0x03, 0xa5, 0x3a, 0x0f, + 0xdb, 0xf1, 0x42, 0x85, 0x27, 0x58, 0xf5, 0xc2, 0x14, 0xad, 0x40, 0xca, + 0x88, 0x64, 0x06, 0x95, 0x69, 0x3f, 0x6f, 0xcd, 0xc7, 0x50, 0xe0, 0x28, + 0xea, 0x78, 0x0c, 0x85, 0x1d, 0x4f, 0x28, 0xc8, 0x51, 0xd4, 0xf2, 0x8c, + 0x85, 0x1d, 0x4f, 0x01, 0x90, 0xa3, 0xa9, 0xe0, 0x32, 0x14, 0x75, 0x3c, + 0x06, 0x42, 0x8e, 0xa7, 0x94, 0x64, 0x28, 0xea, 0x79, 0x46, 0x42, 0x8e, + 0xa7, 0x94, 0x64, 0x28, 0xea, 0x79, 0x46, 0x42, 0x8e, 0xa7, 0x80, 0xc8, + 0x51, 0xd4, 0xf2, 0x8c, 0x85, 0x2a, 0x1c, 0x06, 0x5f, 0xf0, 0xbf, 0xff, + 0xc4, 0x00, 0x5c, 0x10, 0x00, 0x00, 0x04, 0x02, 0x02, 0x07, 0x0f, 0x0d, + 0x0c, 0x07, 0x09, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, + 0x00, 0x05, 0x11, 0x21, 0x06, 0x12, 0x22, 0x31, 0x32, 0x41, 0x72, 0x13, + 0x14, 0x20, 0x42, 0x50, 0x51, 0x61, 0x71, 0x75, 0x81, 0x91, 0xa1, 0xb2, + 0xb5, 0xd1, 0x23, 0x33, 0x34, 0x35, 0x40, 0x52, 0x76, 0x95, 0xb1, 0xb3, + 0xb4, 0xd2, 0xd3, 0x15, 0x30, 0x62, 0x73, 0x82, 0x92, 0x93, 0xa2, 0xa4, + 0xc1, 0xc3, 0xd4, 0x24, 0x43, 0x44, 0x83, 0xa3, 0xc2, 0xf0, 0x10, 0x25, + 0x45, 0x53, 0x54, 0x60, 0x63, 0x84, 0xe1, 0x16, 0xc5, 0xff, 0xda, 0x00, + 0x08, 0x01, 0x01, 0x00, 0x06, 0x3f, 0x02, 0xff, 0x00, 0x60, 0xde, 0x1e, + 0x08, 0xbc, 0x31, 0x74, 0xa1, 0x0b, 0xb6, 0x62, 0x87, 0x94, 0x62, 0xb7, + 0x2d, 0xc3, 0x6d, 0x64, 0xfd, 0x68, 0xad, 0xeb, 0x40, 0xff, 0x00, 0xb2, + 0x8f, 0xaf, 0x15, 0xcc, 0x58, 0x06, 0xdb, 0xc6, 0xfe, 0xd2, 0x2b, 0x9a, + 0xcb, 0x43, 0x6d, 0xf3, 0x5f, 0x6b, 0x15, 0xce, 0xa5, 0x21, 0xb7, 0x31, + 0x67, 0xed, 0xa2, 0xb9, 0xf4, 0x9b, 0xc6, 0x8c, 0xbd, 0xbc, 0x76, 0xfe, + 0x4b, 0xe3, 0x56, 0x3e, 0xde, 0x2a, 0x9f, 0x49, 0x87, 0x6a, 0x68, 0xc7, + 0xdb, 0xc5, 0x53, 0xa9, 0x48, 0xed, 0x4c, 0x59, 0x8f, 0xe3, 0x45, 0x53, + 0x59, 0x68, 0xed, 0x3e, 0x6b, 0xed, 0x62, 0xa9, 0x8b, 0x11, 0xda, 0x76, + 0xdf, 0xda, 0x45, 0x4f, 0x5a, 0x0e, 0xd3, 0x84, 0x7d, 0x78, 0xa9, 0xca, + 0x03, 0xb4, 0xb2, 0x7e, 0xb4, 0x54, 0xaa, 0x63, 0xb4, 0x72, 0xf4, 0xc5, + 0x46, 0x01, 0xdf, 0x0f, 0xec, 0xbc, 0x3c, 0x1d, 0xca, 0x67, 0x2f, 0x9c, + 0xa2, 0xd1, 0x02, 0xdf, 0x51, 0x73, 0x81, 0x03, 0x68, 0xba, 0x65, 0x0f, + 0xac, 0x44, 0xc0, 0xc7, 0x1c, 0x45, 0x18, 0x32, 0x6c, 0xd2, 0x5e, 0x64, + 0x25, 0xd3, 0xdb, 0x83, 0x44, 0x4d, 0x93, 0x4a, 0x6b, 0xb9, 0xfa, 0x46, + 0xa9, 0xef, 0xc0, 0xe7, 0x09, 0x5b, 0x14, 0x03, 0xfe, 0x70, 0x72, 0xf0, + 0xdb, 0xc2, 0x0b, 0xcb, 0xc3, 0x85, 0x31, 0x8b, 0x8c, 0xe8, 0x97, 0xc5, + 0xb1, 0x4f, 0xf1, 0x95, 0x71, 0x17, 0x33, 0x11, 0x26, 0x4b, 0x39, 0x38, + 0x72, 0xa5, 0x87, 0x1e, 0x38, 0xba, 0x9c, 0x38, 0x0d, 0xa0, 0x60, 0x9f, + 0x9a, 0x60, 0x9c, 0x5d, 0x59, 0x03, 0xc2, 0x6d, 0x4c, 0x0e, 0x97, 0x9a, + 0x32, 0x51, 0x77, 0x65, 0x0f, 0xb6, 0xbf, 0xfa, 0x09, 0x88, 0x71, 0x04, + 0xc0, 0xa1, 0x17, 0x76, 0x4c, 0xa0, 0xe5, 0xcf, 0x1d, 0x1b, 0x96, 0xfc, + 0x62, 0xee, 0x7e, 0x43, 0x6d, 0xcc, 0x4e, 0x7f, 0x2b, 0x83, 0x45, 0xd4, + 0xd1, 0x23, 0xfc, 0xac, 0xd3, 0xd6, 0x8a, 0xdd, 0x22, 0x6f, 0xfa, 0xb6, + 0xdf, 0x80, 0x31, 0xd7, 0xcb, 0xbd, 0x2f, 0x30, 0xf9, 0x1a, 0x8c, 0x75, + 0xd5, 0x37, 0xa5, 0xae, 0x3e, 0xe6, 0x71, 0x86, 0xeb, 0x7a, 0x56, 0xf3, + 0xee, 0x67, 0x18, 0x4f, 0x77, 0xa5, 0x6f, 0x7f, 0x29, 0x17, 0xe6, 0x1e, + 0x2c, 0x7d, 0xf9, 0x58, 0xff, 0x00, 0x13, 0xf1, 0x73, 0xef, 0xcb, 0xc7, + 0xf8, 0xa7, 0x8b, 0xde, 0xfb, 0x18, 0xbd, 0x36, 0xde, 0x60, 0xf7, 0xd9, + 0x46, 0x0c, 0xdf, 0xc5, 0xcf, 0xbd, 0x8c, 0x60, 0xcd, 0x7c, 0x58, 0xff, + 0x00, 0xf2, 0xf1, 0x7a, 0x65, 0xe2, 0xb7, 0xff, 0x00, 0x95, 0x8b, 0xcf, + 0xfc, 0x50, 0xfb, 0xf2, 0x51, 0xfb, 0x5e, 0xfc, 0xa5, 0xe7, 0xde, 0xca, + 0x2b, 0x32, 0xdb, 0xf2, 0xb7, 0x01, 0xe5, 0x67, 0x15, 0xad, 0x46, 0x54, + 0xbc, 0xe1, 0xe5, 0x69, 0x15, 0xba, 0x47, 0x7d, 0x9d, 0x1e, 0x56, 0xd1, + 0xd9, 0xcd, 0x43, 0xfe, 0xb9, 0x0b, 0xf8, 0x21, 0x1d, 0x4e, 0x70, 0xd8, + 0x9b, 0x4b, 0x11, 0x2f, 0x20, 0x92, 0x3a, 0x9d, 0x91, 0x51, 0x91, 0x37, + 0x54, 0x9c, 0x87, 0x85, 0x8e, 0xa7, 0x64, 0xef, 0x03, 0x26, 0xc8, 0x26, + 0x21, 0xe4, 0x98, 0xd1, 0x17, 0x36, 0x46, 0xfc, 0xdb, 0x73, 0x77, 0x6a, + 0x79, 0xc7, 0x2a, 0x45, 0xcc, 0xe9, 0xd1, 0xbf, 0x7a, 0x8a, 0x9e, 0x75, + 0x05, 0x23, 0xb6, 0xcb, 0x0e, 0xdb, 0x79, 0x49, 0xf9, 0x72, 0xa3, 0x0c, + 0x5d, 0x3d, 0x29, 0xf2, 0x99, 0x4a, 0xff, 0x00, 0x91, 0x82, 0x71, 0x74, + 0x2d, 0x0f, 0x96, 0xc5, 0x3f, 0xc2, 0x59, 0x18, 0x0c, 0xdd, 0x9c, 0xb1, + 0x52, 0x63, 0xfd, 0x0d, 0xca, 0x66, 0xa3, 0x60, 0xe5, 0x9a, 0x08, 0x06, + 0xd8, 0xa4, 0x6d, 0xa8, 0x29, 0x66, 0x0c, 0xdc, 0x31, 0x38, 0xd4, 0x26, + 0x45, 0x52, 0x39, 0x4e, 0x9d, 0x71, 0x05, 0x8a, 0xcc, 0xc5, 0x0f, 0x82, + 0x4c, 0xd8, 0x76, 0xe0, 0x1c, 0x4b, 0x5e, 0xa0, 0xed, 0x3a, 0x29, 0x1c, + 0xcc, 0xdd, 0x50, 0x94, 0xff, 0x00, 0x9a, 0x89, 0xa8, 0x55, 0x3f, 0x96, + 0x40, 0x01, 0xd2, 0x88, 0xfb, 0xd0, 0xba, 0x72, 0x25, 0x55, 0xd2, 0x80, + 0x20, 0xd1, 0x9d, 0xb5, 0xd2, 0xa6, 0xef, 0xcf, 0x45, 0xd0, 0x24, 0x51, + 0xbf, 0x78, 0x4e, 0x37, 0x25, 0x10, 0xba, 0x31, 0x4e, 0xe2, 0x60, 0xe5, + 0x63, 0x8a, 0x96, 0xd9, 0xdd, 0x92, 0x38, 0x93, 0x2d, 0x62, 0x04, 0x4c, + 0x28, 0x2a, 0x68, 0xa6, 0x15, 0xa8, 0x71, 0x12, 0x20, 0x90, 0x5d, 0xaa, + 0x70, 0xac, 0xd0, 0x25, 0x2a, 0xb4, 0x7f, 0xc6, 0xcf, 0x33, 0x3d, 0x19, + 0x4f, 0x97, 0x22, 0x89, 0x89, 0xc3, 0x18, 0x20, 0xcd, 0x44, 0xb1, 0xa6, + 0xe0, 0xe1, 0x5c, 0x54, 0x2e, 0x4d, 0xf1, 0xaf, 0x5c, 0x53, 0xf6, 0x5c, + 0xe6, 0x1c, 0x05, 0x8b, 0xa4, 0xe9, 0xdb, 0x7b, 0x37, 0x1f, 0xff, 0x00, + 0x46, 0x3b, 0x19, 0x0f, 0x94, 0x77, 0xaa, 0x79, 0xd7, 0x6a, 0x71, 0xc7, + 0x59, 0x69, 0xbe, 0xd1, 0xb9, 0xfc, 0xe1, 0x0f, 0x1d, 0x69, 0x97, 0x8b, + 0xd8, 0x7e, 0x5a, 0x2a, 0x2a, 0x05, 0xc8, 0x6a, 0xd4, 0x9c, 0x84, 0x42, + 0x2a, 0x70, 0xa9, 0x72, 0x0e, 0x24, 0xe4, 0xd1, 0x1d, 0x98, 0xeb, 0xe9, + 0xd5, 0xf5, 0xa2, 0xb7, 0x4e, 0x07, 0x6d, 0x65, 0x3d, 0x68, 0xeb, 0xeb, + 0x6f, 0xaa, 0x7e, 0x98, 0xeb, 0xaa, 0x7c, 0xf3, 0x74, 0xc6, 0x19, 0xbe, + 0x70, 0xc5, 0xf1, 0xe1, 0xf7, 0xbb, 0xf1, 0x51, 0x8d, 0xbc, 0x23, 0x18, + 0x67, 0xf9, 0xc6, 0x8e, 0xb8, 0xa7, 0xcf, 0x37, 0x4c, 0x61, 0x9c, 0x7e, + 0x51, 0xa3, 0x5e, 0x2b, 0x00, 0x1d, 0xb0, 0x8b, 0xb6, 0xcd, 0x4f, 0x96, + 0xdd, 0x13, 0xf2, 0x93, 0x18, 0xae, 0x5d, 0x2d, 0xf1, 0x7b, 0x3f, 0x61, + 0x1d, 0x82, 0xd0, 0x32, 0x1b, 0xa4, 0x9f, 0x20, 0xa5, 0x8e, 0xc5, 0xa3, + 0x21, 0xcb, 0xd4, 0xbc, 0xcb, 0xa2, 0x45, 0xc9, 0x5d, 0x27, 0x93, 0x33, + 0x9a, 0xfd, 0xef, 0x47, 0xc9, 0x17, 0x2e, 0xe6, 0x89, 0xe4, 0x3d, 0xb7, + 0xf4, 0xc4, 0x9d, 0x45, 0x28, 0x3a, 0x23, 0xe2, 0xff, 0x00, 0x90, 0xec, + 0x89, 0xb7, 0x58, 0x76, 0x08, 0xf1, 0x0b, 0x54, 0x44, 0xe3, 0x88, 0x16, + 0x68, 0x91, 0x3b, 0xe5, 0xcb, 0x7e, 0x0a, 0xe2, 0x5e, 0xe1, 0x76, 0x6e, + 0x9b, 0x09, 0x73, 0x66, 0xaa, 0x5c, 0x9c, 0x80, 0x6a, 0xe8, 0x39, 0x29, + 0x12, 0x99, 0x25, 0x4b, 0x59, 0x4e, 0x5b, 0x74, 0x17, 0x20, 0xd2, 0x53, + 0x1c, 0xb1, 0x4d, 0xca, 0x33, 0x46, 0xe4, 0x0c, 0xf8, 0xd8, 0x2a, 0x01, + 0xc5, 0x9b, 0xa4, 0x1d, 0xe0, 0x8e, 0x11, 0x74, 0x82, 0x35, 0x5c, 0x88, + 0x51, 0xa3, 0x5d, 0xda, 0xe6, 0xb5, 0x45, 0xba, 0x46, 0x54, 0xe2, 0x3d, + 0xe9, 0x42, 0x98, 0x75, 0x32, 0x56, 0xb2, 0x5b, 0xe6, 0x0c, 0x5b, 0x5b, + 0xd0, 0x50, 0x28, 0x0d, 0xaa, 0x24, 0x01, 0x35, 0xc9, 0x7b, 0xe5, 0x14, + 0x1b, 0x92, 0x16, 0xdd, 0x53, 0xd0, 0x50, 0x30, 0xc1, 0xd0, 0x44, 0xf4, + 0xa6, 0x22, 0x19, 0xe1, 0xc0, 0x52, 0x02, 0xf0, 0xe4, 0xbd, 0x45, 0x34, + 0x19, 0x36, 0x29, 0x1a, 0x9c, 0xe8, 0xda, 0xaf, 0xf5, 0x0e, 0x00, 0xce, + 0x4e, 0x22, 0x5d, 0x46, 0x0a, 0xc1, 0x35, 0xd2, 0xa7, 0x3a, 0xb9, 0xb5, + 0xa4, 0x51, 0x11, 0xac, 0x53, 0x38, 0x05, 0xd2, 0x8d, 0x15, 0x1e, 0xbe, + 0x87, 0xef, 0x92, 0xa1, 0xc1, 0x08, 0x30, 0xd2, 0x68, 0xdc, 0x73, 0x33, + 0x24, 0xb6, 0x62, 0xf1, 0x0a, 0x69, 0x0a, 0x8d, 0x99, 0xb8, 0x44, 0xd4, + 0x54, 0x62, 0xdf, 0xa0, 0xd7, 0x8c, 0x5b, 0x53, 0x96, 0xa1, 0x28, 0xc3, + 0x67, 0xcd, 0x8c, 0x06, 0x45, 0xca, 0x45, 0x54, 0x82, 0x1f, 0x08, 0x2b, + 0x0d, 0xb0, 0x1a, 0xb4, 0x79, 0xd8, 0x87, 0x12, 0x28, 0xfd, 0x6b, 0x4a, + 0x86, 0x81, 0x14, 0xd3, 0x00, 0xb6, 0x0d, 0xaa, 0x4e, 0x58, 0x49, 0xb9, + 0x46, 0x80, 0x2a, 0x06, 0x39, 0x87, 0x65, 0xc0, 0x99, 0x3f, 0x34, 0x45, + 0x08, 0x3a, 0xe4, 0x58, 0xe5, 0x1a, 0x87, 0x52, 0x57, 0x4b, 0xf5, 0x4f, + 0x1a, 0x11, 0xd1, 0x76, 0x15, 0x40, 0xc0, 0x82, 0x9c, 0x25, 0x12, 0x6f, + 0x14, 0x02, 0xf0, 0x43, 0x86, 0x2a, 0x0d, 0x23, 0x2e, 0x5c, 0x96, 0x95, + 0xd7, 0x99, 0xae, 0x07, 0xab, 0x78, 0x53, 0xe3, 0xd1, 0xc9, 0x59, 0x53, + 0x70, 0x0c, 0x94, 0x71, 0x46, 0xca, 0x8b, 0x9d, 0x3f, 0xc1, 0x08, 0x3e, + 0xc2, 0x28, 0x87, 0x10, 0x8f, 0xf3, 0x6a, 0x4c, 0xac, 0xdd, 0xf2, 0x0f, + 0xcb, 0xc0, 0x08, 0x9a, 0x27, 0x8c, 0xe9, 0xc2, 0x66, 0x8b, 0x80, 0x0f, + 0x8b, 0x5c, 0x13, 0x1f, 0x3b, 0xa3, 0x93, 0xee, 0x38, 0x7a, 0x6b, 0xc8, + 0x5b, 0x21, 0x1f, 0x36, 0x5d, 0x49, 0x94, 0x7c, 0x5c, 0xc3, 0xcd, 0xa5, + 0x13, 0x8d, 0xc6, 0x1f, 0x4d, 0x67, 0xa3, 0x93, 0xee, 0x30, 0x7a, 0x6b, + 0xc8, 0x5b, 0x21, 0x1f, 0x36, 0x1a, 0x93, 0x27, 0xc8, 0x98, 0xf9, 0xb4, + 0x62, 0x71, 0xb8, 0xa3, 0xe9, 0xac, 0xb4, 0x72, 0x7d, 0xc6, 0x0f, 0x4d, + 0x79, 0x0b, 0x64, 0x23, 0xe6, 0xc3, 0xfb, 0x2f, 0xea, 0x3c, 0xa3, 0x22, + 0x61, 0xe6, 0xd2, 0x89, 0xc6, 0xe2, 0x8f, 0xa6, 0xb2, 0xd1, 0xc9, 0xf7, + 0x18, 0x3d, 0x35, 0xe4, 0x2b, 0x90, 0x8f, 0x9b, 0x0d, 0x49, 0x94, 0x7c, + 0x5c, 0xc3, 0xcd, 0xa3, 0x13, 0x8d, 0xc4, 0x37, 0xa7, 0x32, 0xd1, 0xc9, + 0xf7, 0x14, 0xbe, 0x9c, 0xf6, 0x16, 0xc8, 0x47, 0xcd, 0x86, 0xa4, 0xca, + 0x72, 0x26, 0x1e, 0x6d, 0x28, 0x9c, 0x6e, 0x21, 0xbd, 0x39, 0x96, 0x8e, + 0x4f, 0xb8, 0xa5, 0xf4, 0xe7, 0xb0, 0xae, 0x42, 0x5e, 0x6c, 0x34, 0x58, + 0x7f, 0x54, 0xfd, 0x11, 0x87, 0xf5, 0x4d, 0xd1, 0x18, 0x7c, 0x46, 0xf5, + 0x63, 0x0f, 0xea, 0x9b, 0xa2, 0x30, 0xfe, 0xa9, 0xba, 0x23, 0x0b, 0xea, + 0x9b, 0xa2, 0x30, 0xb8, 0x8d, 0xd1, 0x18, 0x7f, 0x54, 0xdd, 0x11, 0x87, + 0xf5, 0x4d, 0xd1, 0x18, 0x7f, 0x54, 0xdd, 0x11, 0x87, 0xf5, 0x4d, 0xea, + 0xc6, 0x1f, 0xd5, 0x3f, 0x44, 0x61, 0xfd, 0x53, 0xf4, 0x47, 0x5c, 0xfa, + 0x87, 0xf5, 0x63, 0xae, 0xfd, 0x45, 0x3d, 0x48, 0xeb, 0xbf, 0x51, 0x5f, + 0x52, 0x2b, 0x5b, 0xf8, 0x6a, 0xfa, 0x91, 0xd7, 0xff, 0x00, 0x84, 0xb7, + 0xb3, 0x8e, 0xc8, 0xfe, 0x12, 0xfe, 0xce, 0x3b, 0x27, 0xf8, 0x2b, 0xfb, + 0x28, 0xec, 0xaf, 0xe0, 0x39, 0xf6, 0x51, 0xd9, 0x7f, 0xc0, 0x73, 0xec, + 0x63, 0xb3, 0x3e, 0xce, 0xeb, 0xd8, 0xc7, 0x66, 0xfd, 0x9d, 0xdf, 0xb0, + 0x8e, 0xce, 0xfb, 0x33, 0xcf, 0xcb, 0xc7, 0x67, 0xfd, 0x99, 0xe7, 0xe5, + 0xe3, 0xb3, 0xfe, 0xca, 0xf7, 0xf2, 0xf1, 0xd9, 0xff, 0x00, 0x65, 0x7b, + 0xf9, 0x78, 0xec, 0xff, 0x00, 0xb2, 0xbd, 0xfc, 0xbc, 0x76, 0x7f, 0xd9, + 0x5e, 0xfe, 0x5f, 0x45, 0x28, 0xf8, 0xb9, 0x87, 0x9b, 0x4a, 0x27, 0x1b, + 0x88, 0x6f, 0x4e, 0x65, 0xa3, 0x93, 0xee, 0x21, 0x7d, 0x39, 0xec, 0x2b, + 0x90, 0x8f, 0x9b, 0x0d, 0x49, 0x94, 0xfc, 0x5c, 0xc3, 0xcd, 0xa5, 0x13, + 0x8d, 0xc3, 0x37, 0xa7, 0x32, 0xd1, 0xc9, 0xb7, 0x10, 0xbe, 0x9c, 0xf6, + 0x15, 0xc8, 0x4b, 0xcd, 0x86, 0xa4, 0xca, 0x7e, 0x2e, 0x61, 0xe6, 0xd1, + 0x89, 0xc6, 0xe1, 0x9b, 0xd3, 0xd8, 0xe8, 0xe4, 0xdb, 0x88, 0x5f, 0x4e, + 0x7d, 0x0a, 0xe4, 0x23, 0xc8, 0x0d, 0x49, 0x94, 0xe4, 0x4c, 0x3c, 0xda, + 0x31, 0x38, 0xdc, 0x23, 0x7a, 0x7b, 0x1d, 0x1c, 0x9b, 0x70, 0xcb, 0xe9, + 0xef, 0xa1, 0x5c, 0x84, 0xb9, 0x01, 0xa9, 0x32, 0x9c, 0x87, 0xfc, 0x84, + 0xa2, 0x73, 0xb8, 0x46, 0xf4, 0xf6, 0x3a, 0x39, 0x36, 0xe1, 0x97, 0xd3, + 0xdf, 0x42, 0xb9, 0x08, 0xf2, 0x03, 0x52, 0x65, 0x39, 0x0f, 0xf9, 0x09, + 0x44, 0xe7, 0x70, 0x4d, 0xe9, 0xec, 0x74, 0x72, 0x6d, 0xc2, 0x2f, 0xa7, + 0xbe, 0x85, 0x72, 0x52, 0xe4, 0x6a, 0x4c, 0xa7, 0x21, 0xff, 0x00, 0x21, + 0x28, 0x9c, 0xee, 0x09, 0xfd, 0x3d, 0x86, 0x8e, 0x4d, 0xb8, 0x45, 0xf4, + 0xf7, 0xd0, 0xa6, 0x42, 0x5c, 0x80, 0xd4, 0x99, 0x4e, 0x43, 0xfe, 0x42, + 0x51, 0x39, 0xdc, 0x13, 0xf3, 0x83, 0x0d, 0x1c, 0x9b, 0x70, 0x8b, 0xce, + 0x0f, 0xa1, 0x4c, 0x94, 0xb9, 0x1a, 0x93, 0x2a, 0xc8, 0x7f, 0xc8, 0x4a, + 0x27, 0x3b, 0x82, 0x7e, 0x70, 0x61, 0xa3, 0x93, 0x6e, 0x09, 0x79, 0xc1, + 0xf4, 0x2b, 0x90, 0x9f, 0x20, 0x35, 0x26, 0x55, 0x90, 0xff, 0x00, 0x90, + 0x8c, 0x4e, 0x77, 0x00, 0xfc, 0xe0, 0xc3, 0x47, 0x26, 0xdc, 0x12, 0x73, + 0x83, 0xe8, 0x53, 0x21, 0x2e, 0x40, 0x6a, 0x4c, 0xab, 0x21, 0xf7, 0x21, + 0x28, 0x9c, 0xee, 0x01, 0xf9, 0xc1, 0x86, 0x8e, 0x4d, 0xb8, 0x24, 0xe7, + 0x07, 0xf0, 0xa6, 0x42, 0x5c, 0x8d, 0x49, 0x95, 0xe4, 0x3e, 0xe4, 0x23, + 0x13, 0x9d, 0xc0, 0x3f, 0x38, 0x30, 0xd1, 0xc9, 0xb7, 0x04, 0x9c, 0xe0, + 0xfe, 0x14, 0xc9, 0x4b, 0x90, 0x1a, 0x93, 0x2c, 0xc8, 0x7d, 0xc8, 0x4a, + 0x27, 0x3b, 0x80, 0x7e, 0x71, 0x97, 0xe8, 0xe4, 0xdb, 0x80, 0x4e, 0x70, + 0x7f, 0x0a, 0x64, 0x25, 0xc8, 0x0d, 0x49, 0x96, 0x64, 0x3d, 0xe4, 0x27, + 0x13, 0x9f, 0x07, 0xcf, 0xce, 0x32, 0xfd, 0x1c, 0x9b, 0x70, 0x09, 0xce, + 0x0f, 0xe1, 0x4c, 0x84, 0xb9, 0x21, 0xa9, 0x32, 0xdc, 0x87, 0xbc, 0x84, + 0xe2, 0x73, 0xe0, 0xf9, 0xf9, 0xc6, 0x5f, 0xa3, 0x92, 0xee, 0x01, 0x39, + 0xc5, 0xfc, 0x29, 0x90, 0x9f, 0x23, 0x52, 0x65, 0xb9, 0x0f, 0x79, 0x09, + 0xc4, 0xe7, 0xc1, 0xf5, 0x39, 0xc6, 0x5f, 0xa3, 0x93, 0x78, 0x3e, 0x4e, + 0x71, 0x98, 0x42, 0x99, 0x09, 0x72, 0x43, 0x52, 0x65, 0xd9, 0x0f, 0x39, + 0x09, 0xc4, 0xe7, 0xc1, 0xe5, 0x39, 0xc6, 0x5f, 0xa3, 0x93, 0x78, 0x3e, + 0x4e, 0x71, 0x98, 0x42, 0x99, 0x09, 0xf2, 0x35, 0x26, 0x5f, 0x92, 0xef, + 0x90, 0x9c, 0x4e, 0x7c, 0x1e, 0x3f, 0x38, 0xcb, 0xf4, 0x72, 0x5f, 0x07, + 0xc9, 0xce, 0x33, 0x08, 0x53, 0x21, 0x2e, 0x48, 0x6a, 0x4c, 0xbf, 0x21, + 0xdf, 0x20, 0x91, 0x39, 0xf0, 0x79, 0x4e, 0x71, 0x97, 0x68, 0xe4, 0xbe, + 0x0f, 0xa7, 0xce, 0x33, 0x08, 0x53, 0x21, 0x3e, 0x4e, 0xa4, 0xb0, 0xc8, + 0x77, 0xc8, 0x24, 0x4e, 0xbc, 0x1e, 0x53, 0x9c, 0x65, 0xda, 0x39, 0x2f, + 0x83, 0xc9, 0xf3, 0x8c, 0xc2, 0x14, 0xc8, 0x4f, 0x91, 0xa9, 0x2c, 0x72, + 0x5d, 0x72, 0x09, 0x13, 0x9f, 0x07, 0x54, 0xe7, 0x29, 0x76, 0x8e, 0x4b, + 0xe0, 0xf2, 0x7c, 0xe5, 0x30, 0x85, 0x32, 0x13, 0xe4, 0xea, 0x4b, 0x2c, + 0x97, 0x5c, 0x82, 0x44, 0xe7, 0xc1, 0xd5, 0x39, 0xca, 0x5d, 0xa3, 0x92, + 0xf8, 0x3c, 0x9f, 0x38, 0xcc, 0x60, 0xf9, 0x29, 0xf2, 0x75, 0x25, 0x96, + 0x43, 0x9e, 0x41, 0x62, 0x73, 0xe0, 0xea, 0x9c, 0xe5, 0x2e, 0xd1, 0xc9, + 0x7c, 0x1e, 0x4f, 0x9c, 0x66, 0x30, 0x7c, 0x84, 0xf9, 0x3a, 0x92, 0xcf, + 0x25, 0xc7, 0x24, 0xb1, 0x39, 0xf0, 0x71, 0x4e, 0x72, 0x96, 0xe8, 0xe4, + 0xbe, 0x0f, 0x27, 0xce, 0x53, 0x18, 0x53, 0x21, 0x3e, 0x4e, 0xa4, 0xb4, + 0xc9, 0x71, 0xc8, 0x2c, 0x4e, 0xbc, 0x1d, 0x53, 0x9c, 0xa5, 0xba, 0x39, + 0x2f, 0x83, 0xa9, 0xf3, 0x94, 0xc6, 0x0f, 0x90, 0x9f, 0x27, 0x52, 0x5a, + 0x64, 0xb8, 0xe4, 0x04, 0x4e, 0xbc, 0x1c, 0x57, 0x9c, 0xa5, 0xba, 0x39, + 0x2f, 0x83, 0xa9, 0xf3, 0x94, 0xc6, 0x0f, 0x90, 0x9f, 0x27, 0x52, 0x5a, + 0xe4, 0xaf, 0xc9, 0x08, 0x9d, 0x78, 0x38, 0xaf, 0x39, 0x4b, 0x74, 0x72, + 0x5f, 0x07, 0x53, 0xe7, 0x29, 0x8c, 0x1f, 0x21, 0x3e, 0x4e, 0xa4, 0xb6, + 0xc9, 0x5f, 0x92, 0x11, 0x3a, 0xf0, 0x71, 0x5e, 0x72, 0x96, 0xe8, 0xe4, + 0xbe, 0x0e, 0xa7, 0xce, 0x53, 0x18, 0x3e, 0x42, 0x7e, 0x4d, 0x49, 0x6f, + 0x92, 0xbf, 0x24, 0x22, 0x75, 0xe0, 0xe2, 0xbc, 0xe5, 0x2d, 0xd1, 0xc8, + 0x8f, 0xdf, 0x48, 0x2d, 0x7e, 0x64, 0xc1, 0xe0, 0xfe, 0x24, 0x0f, 0xc5, + 0xa7, 0xf7, 0xea, 0x4a, 0x3f, 0x16, 0xb7, 0x90, 0xb1, 0x3b, 0x37, 0x7b, + 0x63, 0xc6, 0x2f, 0xce, 0x98, 0xb0, 0x1f, 0xe5, 0xd1, 0xd8, 0xca, 0x9d, + 0xf4, 0xad, 0xe1, 0x3e, 0x63, 0xa0, 0x37, 0xf3, 0xc7, 0xee, 0x93, 0xf2, + 0x9f, 0x45, 0x83, 0xc6, 0x1d, 0x31, 0x7b, 0x8c, 0x3a, 0x63, 0x07, 0x8c, + 0x3a, 0x63, 0x07, 0x8c, 0x3a, 0x63, 0x07, 0x8c, 0x3a, 0x63, 0x07, 0x8c, + 0x3a, 0x62, 0xf7, 0x18, 0x74, 0xc5, 0xee, 0x30, 0xe9, 0x8b, 0xdc, 0x61, + 0xd3, 0x18, 0x3c, 0x61, 0xd3, 0x18, 0x3c, 0x61, 0xd3, 0x17, 0xb8, 0xc3, + 0xa6, 0x30, 0x78, 0xc3, 0xa6, 0x30, 0x78, 0xc3, 0xa6, 0x30, 0x78, 0xc3, + 0xa6, 0x30, 0x78, 0xc3, 0xa6, 0x2f, 0x71, 0x87, 0x4c, 0x5e, 0xe3, 0x0e, + 0x98, 0xbd, 0xc6, 0x1d, 0x31, 0x7b, 0x8c, 0x3a, 0x62, 0xf7, 0x18, 0x74, + 0xc5, 0xee, 0x30, 0xe9, 0x8b, 0xdc, 0x61, 0xd3, 0x17, 0xb8, 0xc3, 0xa6, + 0x2f, 0x71, 0x87, 0x4c, 0x60, 0xf1, 0x87, 0x4c, 0x5e, 0xe3, 0x0e, 0x98, + 0xbd, 0xc6, 0x1d, 0x31, 0x83, 0xc6, 0x1d, 0x31, 0x83, 0xc6, 0x5e, 0x9d, + 0x12, 0x7f, 0x12, 0xa8, 0xf1, 0xa7, 0x16, 0x4a, 0xa7, 0x7b, 0x28, 0x6a, + 0x4f, 0x9e, 0xec, 0x0d, 0xf8, 0x7a, 0x3b, 0x10, 0x5f, 0x11, 0xd1, 0x9b, + 0xa5, 0xbe, 0x99, 0xd8, 0x9b, 0xf1, 0x42, 0x0a, 0x3a, 0xe8, 0x97, 0x88, + 0xc7, 0xd4, 0x9a, 0x7b, 0xd6, 0xc7, 0xe3, 0x39, 0x02, 0x2c, 0xb9, 0x6e, + 0xf1, 0xb4, 0xa5, 0x2f, 0xa4, 0x51, 0xe9, 0xbf, 0x0b, 0x47, 0x62, 0x8e, + 0xa8, 0xeb, 0x53, 0x19, 0x82, 0x14, 0xeb, 0x67, 0x86, 0xed, 0xd4, 0xa3, + 0x7f, 0x3a, 0xf1, 0x43, 0x73, 0x6b, 0x94, 0xe5, 0xe0, 0x12, 0x8f, 0xde, + 0x3a, 0x92, 0xb9, 0xb5, 0x93, 0x48, 0xbc, 0x26, 0x38, 0xfd, 0xc1, 0x16, + 0x5a, 0xfa, 0x8b, 0x85, 0xdf, 0xcb, 0x1a, 0x94, 0x7e, 0x13, 0x44, 0x1d, + 0xaa, 0x7e, 0x27, 0x89, 0xe8, 0xd4, 0x74, 0x01, 0x48, 0xca, 0xa6, 0xf2, + 0xd7, 0xb4, 0xeb, 0x15, 0x43, 0x29, 0x2e, 0x1d, 0xe1, 0x17, 0xc5, 0xdf, + 0xa2, 0x12, 0x36, 0xb2, 0xb4, 0x7c, 0xe2, 0x1b, 0xa0, 0x35, 0x25, 0x73, + 0xeb, 0xab, 0x6b, 0xf3, 0x13, 0x2f, 0xde, 0x23, 0x05, 0x73, 0x45, 0x73, + 0x39, 0xcc, 0xc9, 0xe5, 0x3a, 0xe5, 0x4c, 0x51, 0x60, 0x1c, 0x02, 0xc8, + 0xda, 0x3b, 0x2a, 0x62, 0x42, 0xdb, 0xa8, 0x79, 0x33, 0xb5, 0xd2, 0x20, + 0x05, 0x22, 0x75, 0x99, 0x17, 0x3f, 0x22, 0x52, 0x87, 0x7c, 0x2a, 0xb7, + 0x20, 0x17, 0xe1, 0x51, 0x06, 0xa2, 0xf9, 0x40, 0x14, 0xf9, 0x83, 0x5f, + 0xd5, 0xa7, 0x52, 0x4a, 0x61, 0xbe, 0x70, 0x32, 0x9f, 0x48, 0x34, 0x97, + 0x8a, 0x88, 0xb1, 0x79, 0x71, 0xc2, 0xd5, 0x52, 0x4a, 0x90, 0x70, 0xb1, + 0x46, 0xa1, 0x2a, 0xef, 0xed, 0x9f, 0xae, 0x41, 0xd9, 0x22, 0xae, 0x4e, + 0x41, 0xda, 0xd1, 0x89, 0x4c, 0x00, 0x25, 0x30, 0x08, 0x08, 0x0d, 0x60, + 0x20, 0x35, 0x08, 0x08, 0x6b, 0x0c, 0x59, 0x0c, 0x84, 0xc0, 0x36, 0x92, + 0xf9, 0xa3, 0xc6, 0xc8, 0x80, 0xe9, 0x9a, 0x66, 0x86, 0x33, 0x53, 0xfe, + 0xf1, 0xb1, 0xd2, 0x3f, 0xca, 0x83, 0xa6, 0x3a, 0x43, 0x98, 0xbc, 0x03, + 0x46, 0xa3, 0x95, 0x30, 0xbe, 0xa1, 0x8a, 0x40, 0xf9, 0x43, 0x47, 0x10, + 0x57, 0x16, 0x3d, 0x22, 0x29, 0x69, 0x24, 0xc6, 0x6c, 0xc5, 0xaa, 0x80, + 0x1a, 0x56, 0xb9, 0xb1, 0x33, 0xc9, 0xb6, 0x93, 0x6c, 0x0a, 0x1c, 0x76, + 0x0b, 0x00, 0x00, 0x14, 0x00, 0x05, 0x00, 0x01, 0x78, 0x00, 0x2f, 0x00, + 0x7b, 0xc3, 0x59, 0xc9, 0x49, 0x43, 0x7b, 0x20, 0x96, 0xa3, 0x6c, 0xa6, + 0x23, 0x3e, 0x97, 0x50, 0xd1, 0x60, 0xdb, 0x06, 0xb9, 0xc4, 0x76, 0x69, + 0x8b, 0x6c, 0x4a, 0x94, 0x0d, 0xbe, 0x5b, 0x91, 0xf2, 0x00, 0xef, 0xea, + 0x3d, 0xb6, 0x24, 0x8a, 0x26, 0xf9, 0x46, 0xb8, 0x2f, 0x10, 0x98, 0x77, + 0xa1, 0xdc, 0xe9, 0x42, 0x5b, 0x36, 0xb1, 0xb9, 0x79, 0xf3, 0x33, 0x62, + 0x09, 0x8c, 0xca, 0xd9, 0xaa, 0x21, 0xad, 0xd8, 0x99, 0xf8, 0x76, 0x04, + 0x08, 0x3a, 0xc3, 0xef, 0x2e, 0xdd, 0x20, 0x9d, 0xbb, 0xeb, 0x1e, 0x54, + 0xb3, 0x94, 0x28, 0x0b, 0xb1, 0x41, 0x12, 0x89, 0x26, 0x09, 0x87, 0xc1, + 0xce, 0x87, 0x3a, 0xe2, 0x1a, 0x63, 0x36, 0x24, 0x02, 0xa5, 0xc2, 0x4a, + 0xef, 0xe4, 0x8d, 0x47, 0x0f, 0xbf, 0x7b, 0x51, 0xc5, 0x63, 0x61, 0x2b, + 0x77, 0xf2, 0x42, 0xa2, 0x06, 0xfd, 0xff, 0x00, 0x95, 0x0c, 0xdc, 0xae, + 0x4b, 0x47, 0xd6, 0x40, 0xa9, 0xa7, 0x4e, 0x29, 0x0a, 0x0e, 0x08, 0x2e, + 0x52, 0x91, 0x81, 0x07, 0x63, 0x3a, 0x10, 0x8b, 0x80, 0x62, 0x33, 0x83, + 0xfb, 0xca, 0x88, 0x2c, 0x42, 0xa8, 0x92, 0xc9, 0x9d, 0x25, 0x53, 0x30, + 0x52, 0x53, 0xa6, 0xa1, 0x44, 0x87, 0x21, 0x83, 0x19, 0x4c, 0x51, 0x10, + 0x10, 0xd6, 0x18, 0x9e, 0xd8, 0xe2, 0xa0, 0x39, 0x9b, 0x17, 0x8a, 0x03, + 0x51, 0x37, 0xeb, 0x65, 0xee, 0x03, 0x36, 0x66, 0xa6, 0xcd, 0xbb, 0x65, + 0x53, 0xb6, 0xd6, 0x3d, 0xb0, 0x62, 0x83, 0xa4, 0x3a, 0x43, 0x55, 0xb2, + 0x5b, 0xe5, 0x1d, 0xf0, 0xa3, 0x51, 0x48, 0x98, 0x69, 0xcd, 0x40, 0xed, + 0x5f, 0x30, 0xef, 0x16, 0x98, 0x90, 0xd8, 0xe2, 0x40, 0x39, 0x9b, 0xe7, + 0x89, 0xe7, 0xa1, 0x27, 0xea, 0xa5, 0xed, 0x83, 0x37, 0x78, 0x7a, 0x71, + 0x5a, 0xb6, 0x49, 0x4b, 0x5a, 0x6f, 0x9e, 0xd0, 0xb7, 0xc6, 0x13, 0x45, + 0x12, 0x15, 0x34, 0x91, 0x4c, 0x89, 0x24, 0x99, 0x42, 0x82, 0x91, 0x34, + 0xca, 0x05, 0x21, 0x0a, 0x18, 0x8a, 0x52, 0x80, 0x00, 0x06, 0xb0, 0x7b, + 0xd4, 0x9e, 0xcc, 0xdb, 0x27, 0x81, 0xfd, 0xcb, 0x35, 0x12, 0x86, 0x90, + 0xc2, 0x75, 0xa5, 0xeb, 0x9e, 0x8d, 0x63, 0x67, 0x86, 0xe6, 0x38, 0xf7, + 0xed, 0x89, 0xad, 0x09, 0xae, 0x18, 0xfa, 0x99, 0xfc, 0xa4, 0x1f, 0x28, + 0x70, 0x6a, 0x2a, 0x8e, 0x07, 0x17, 0x53, 0x27, 0x94, 0xe3, 0xc1, 0x40, + 0x70, 0xc4, 0xee, 0xcc, 0xdc, 0xa7, 0x86, 0x3e, 0xe2, 0x4a, 0x4c, 0x60, + 0xd2, 0x10, 0x48, 0xbc, 0xc9, 0x62, 0x53, 0x88, 0xc7, 0xce, 0xa8, 0x11, + 0x42, 0xf7, 0x8e, 0x53, 0xa7, 0x08, 0x3d, 0xee, 0x6f, 0x20, 0x75, 0x46, + 0x67, 0x32, 0x66, 0xa2, 0x24, 0x38, 0x85, 0x39, 0x8b, 0x80, 0xea, 0x8d, + 0x5c, 0x06, 0xcb, 0x77, 0x24, 0x49, 0x60, 0xd7, 0xb4, 0xa2, 0x1f, 0x4a, + 0x9f, 0x26, 0x29, 0x3c, 0x64, 0xba, 0xec, 0x9c, 0xa6, 0x6b, 0xe9, 0x39, + 0x6c, 0xa1, 0x93, 0x30, 0x7c, 0x95, 0x09, 0xbf, 0x02, 0x03, 0x50, 0x80, + 0x88, 0x08, 0x6c, 0x86, 0xa1, 0x80, 0x05, 0x62, 0x22, 0x00, 0x01, 0xae, + 0x23, 0x50, 0x43, 0x29, 0x5b, 0x22, 0x0a, 0xcf, 0x1e, 0xae, 0x83, 0x26, + 0xc9, 0x13, 0x09, 0x57, 0x2e, 0x94, 0x2a, 0x65, 0x28, 0x65, 0xaa, 0x70, + 0x0d, 0x8a, 0x62, 0x51, 0x63, 0xed, 0x68, 0x12, 0x4b, 0x59, 0xa6, 0x89, + 0xd4, 0x00, 0xa3, 0x37, 0x72, 0x3d, 0x51, 0xdb, 0x9d, 0xb7, 0x0e, 0x8e, + 0xb2, 0xc3, 0xad, 0x6f, 0x47, 0xbe, 0x36, 0xb2, 0x26, 0xc9, 0x5a, 0xb1, + 0xb2, 0x54, 0x28, 0x70, 0x25, 0x0b, 0x92, 0xcd, 0x99, 0x01, 0x48, 0xb5, + 0xb6, 0x22, 0x8b, 0x96, 0xc2, 0xdd, 0x52, 0xd3, 0x40, 0xa8, 0xa1, 0x5c, + 0x9a, 0xbb, 0x53, 0x40, 0x2a, 0x18, 0x2b, 0x5f, 0xf8, 0xc0, 0xbf, 0xc2, + 0x14, 0x0e, 0xdd, 0x3a, 0x87, 0x9a, 0x0e, 0x0a, 0x55, 0xfc, 0xb1, 0xc1, + 0xe0, 0x0a, 0x47, 0x82, 0x16, 0x9f, 0xb8, 0x4a, 0xd9, 0x8d, 0x8c, 0x21, + 0x6c, 0x88, 0x98, 0x2e, 0x4f, 0x36, 0x78, 0x53, 0xa4, 0xda, 0x8c, 0x46, + 0x16, 0xe8, 0x03, 0x85, 0xf5, 0xd3, 0x54, 0x1b, 0x9b, 0x18, 0x0f, 0xbe, + 0xcd, 0x65, 0x89, 0xa7, 0x6f, 0x30, 0x40, 0x9e, 0xe9, 0x4a, 0x6a, 0xba, + 0xf7, 0x45, 0x91, 0x4c, 0x74, 0xd3, 0x26, 0xb0, 0xbb, 0x48, 0x56, 0x65, + 0x4e, 0x20, 0x72, 0x23, 0x8a, 0x0c, 0x5a, 0x3a, 0xa1, 0x6b, 0x00, 0x1b, + 0xe0, 0xa1, 0x31, 0x6f, 0xd6, 0x5d, 0xfd, 0x43, 0x00, 0xa3, 0xaa, 0x1a, + 0xe8, 0x75, 0xc4, 0xe7, 0xbc, 0x1b, 0xd5, 0x04, 0x4b, 0x18, 0x2c, 0x9d, + 0xa4, 0xc5, 0xe9, 0x7d, 0xd5, 0x9b, 0x52, 0x14, 0x1f, 0x3e, 0xbd, 0x29, + 0x4d, 0x98, 0x9b, 0x65, 0xa2, 0x00, 0x8b, 0x4d, 0x6b, 0x64, 0x4c, 0x6d, + 0x30, 0xfb, 0xf3, 0xb5, 0x1b, 0xa7, 0x99, 0xca, 0xec, 0x84, 0x0f, 0x37, + 0x63, 0x40, 0x50, 0x9a, 0x6b, 0xaa, 0x71, 0xf7, 0x45, 0xb1, 0x71, 0x06, + 0x64, 0xea, 0xd9, 0x52, 0xa6, 0x5a, 0x93, 0x41, 0xcb, 0x72, 0x84, 0x1a, + 0x8c, 0x15, 0x2e, 0xcb, 0xbf, 0x84, 0x1c, 0x3c, 0x54, 0x6a, 0x09, 0x69, + 0x0b, 0x84, 0xee, 0xcd, 0xbd, 0x82, 0x1b, 0xe3, 0xc4, 0x03, 0x0c, 0x8a, + 0xe1, 0x3b, 0x79, 0x54, 0x84, 0x02, 0x71, 0x31, 0xa4, 0x3a, 0x9a, 0x86, + 0x44, 0xe0, 0x0c, 0x5a, 0x9b, 0x10, 0xe6, 0xee, 0xed, 0x0c, 0x74, 0xc7, + 0x0d, 0xba, 0x2e, 0x35, 0xbd, 0xfd, 0xcb, 0x96, 0xc9, 0xdb, 0xcd, 0x2c, + 0x74, 0x4d, 0x37, 0x65, 0x6a, 0x14, 0xa8, 0xa2, 0x09, 0x93, 0xfb, 0xc5, + 0xb1, 0x71, 0xf5, 0x46, 0xa0, 0x2b, 0x14, 0x85, 0x0a, 0x54, 0x5d, 0xaa, + 0x04, 0x0b, 0xf1, 0x6e, 0x5c, 0x24, 0xee, 0xc3, 0x6b, 0x4e, 0x1c, 0x15, + 0xef, 0x6a, 0x0e, 0x68, 0x6c, 0x23, 0xdd, 0x8e, 0xd6, 0x90, 0x38, 0x2b, + 0xdf, 0x84, 0x5f, 0x3a, 0x4e, 0xd2, 0x69, 0x64, 0xa6, 0x24, 0xd9, 0xd5, + 0xb0, 0x50, 0x74, 0xda, 0x18, 0x94, 0x4b, 0x1b, 0x8e, 0x3a, 0x0a, 0xd8, + 0xc2, 0xea, 0xd4, 0x6b, 0x22, 0xaf, 0x15, 0x20, 0xe0, 0xfb, 0xf8, 0x80, + 0x85, 0x20, 0x35, 0x08, 0x0d, 0x60, 0x20, 0x38, 0x86, 0x26, 0xb2, 0x94, + 0x88, 0x25, 0x97, 0x38, 0x37, 0xba, 0x52, 0x9a, 0xaa, 0xce, 0x2f, 0x2d, + 0x8e, 0x08, 0x97, 0x5c, 0x1a, 0x2c, 0x0b, 0x33, 0xd9, 0xcc, 0x2d, 0x87, + 0x0a, 0x0c, 0x4d, 0x2e, 0x11, 0x32, 0x47, 0xa2, 0xb0, 0xee, 0xf2, 0x13, + 0x4b, 0x84, 0x7c, 0x90, 0xbf, 0xc3, 0x7b, 0x7e, 0x25, 0x32, 0x43, 0x94, + 0x46, 0x5e, 0x99, 0xfd, 0xd0, 0x9b, 0x08, 0x00, 0xd0, 0x12, 0xe6, 0x74, + 0x1d, 0x44, 0x84, 0x43, 0x07, 0x3d, 0x1f, 0x32, 0x66, 0x53, 0x69, 0x4c, + 0xe0, 0x07, 0x14, 0x01, 0x4a, 0x00, 0x52, 0x94, 0x00, 0xa5, 0x29, 0x42, + 0x80, 0x28, 0x05, 0x40, 0x00, 0x01, 0x50, 0x00, 0x05, 0x40, 0x1d, 0xc0, + 0x95, 0x91, 0x34, 0x4e, 0xda, 0x61, 0x63, 0x27, 0x15, 0x55, 0xb5, 0x0b, + 0xa5, 0x65, 0x2e, 0x04, 0xa5, 0x76, 0x51, 0xa2, 0xb1, 0xce, 0xca, 0x02, + 0x4e, 0x82, 0x9a, 0x93, 0x48, 0xae, 0x47, 0x4c, 0x30, 0x0b, 0x16, 0xfa, + 0x75, 0xfc, 0x81, 0xbf, 0xc1, 0x50, 0xf0, 0xf7, 0x78, 0xac, 0x6b, 0xea, + 0x57, 0xf2, 0x02, 0xf7, 0x08, 0xd2, 0x3c, 0x10, 0xe2, 0xc9, 0xdd, 0xa5, + 0x6a, 0xfe, 0xc9, 0x4e, 0x06, 0x6d, 0x6c, 0x17, 0x69, 0x49, 0xdb, 0x18, + 0xc5, 0x6d, 0x45, 0x35, 0x86, 0x7b, 0x5b, 0x35, 0x72, 0x38, 0x94, 0x44, + 0x1a, 0x1b, 0x17, 0x70, 0xae, 0xd5, 0xca, 0x65, 0x59, 0xbb, 0x94, 0x54, + 0x6e, 0xba, 0x47, 0x0a, 0x48, 0xaa, 0x2b, 0x10, 0x53, 0x55, 0x33, 0x06, + 0x32, 0x9c, 0x86, 0x12, 0x88, 0x6b, 0x0c, 0x4d, 0xec, 0x79, 0x7b, 0x63, + 0x22, 0xdd, 0x61, 0x3b, 0x25, 0x4d, 0xfb, 0x44, 0xb9, 0xc7, 0x54, 0x6a, + 0xa6, 0xb0, 0x8e, 0x64, 0x60, 0x22, 0xb4, 0x54, 0x0b, 0x11, 0x52, 0xe9, + 0x60, 0xe9, 0xeb, 0x0d, 0xce, 0xc9, 0x46, 0xf7, 0x47, 0x0f, 0x76, 0x91, + 0x3d, 0x71, 0xa4, 0xdb, 0x05, 0x0a, 0xc7, 0xff, 0x00, 0x22, 0x51, 0x63, + 0x68, 0x5b, 0x11, 0x17, 0x2b, 0x02, 0x8f, 0xd5, 0x27, 0xec, 0xd2, 0xc6, + 0xdd, 0x51, 0xda, 0xba, 0xc0, 0x6c, 0xc8, 0xb9, 0x9a, 0x34, 0xd0, 0x06, + 0x5c, 0xe8, 0x93, 0x4d, 0x0d, 0xda, 0x35, 0x4c, 0xa8, 0xb6, 0x6a, 0x8a, + 0x4d, 0xdb, 0xa2, 0x40, 0xa0, 0x89, 0x22, 0x89, 0x01, 0x34, 0x93, 0x28, + 0x62, 0x29, 0x08, 0x50, 0x28, 0x6c, 0x07, 0x71, 0x35, 0xb2, 0xe6, 0x69, + 0xd2, 0xf2, 0x45, 0xfa, 0x3b, 0xfb, 0x50, 0xba, 0x56, 0x54, 0xe1, 0x4b, + 0x93, 0x8e, 0x31, 0xce, 0x6e, 0x8d, 0x4e, 0xc2, 0x4e, 0x57, 0x38, 0xd4, + 0x48, 0x2a, 0xe5, 0xbe, 0x4a, 0x8d, 0xb2, 0x41, 0xf5, 0x47, 0xca, 0x3d, + 0xda, 0x65, 0xcd, 0x7c, 0xf8, 0x39, 0x01, 0xeb, 0x0f, 0x90, 0x21, 0xe5, + 0x97, 0xbc, 0x4a, 0x87, 0xb6, 0x40, 0x39, 0xde, 0x5f, 0x6c, 0x17, 0x49, + 0x49, 0xda, 0xa9, 0x84, 0x18, 0xcb, 0x9f, 0x9d, 0x90, 0x4e, 0x21, 0x78, + 0xc9, 0x35, 0x6a, 0xa1, 0x46, 0x83, 0xf7, 0x1b, 0xa6, 0x0f, 0x12, 0x2a, + 0xcd, 0x5e, 0x37, 0x59, 0xab, 0x94, 0x4d, 0x82, 0xa2, 0x0b, 0x90, 0xc9, + 0xaa, 0x41, 0xca, 0x21, 0x84, 0x22, 0x71, 0x63, 0x8e, 0xa9, 0x39, 0x5a, + 0x2e, 0x39, 0xdd, 0x51, 0x0e, 0xc8, 0x62, 0xb9, 0x41, 0x56, 0xab, 0x6b, + 0x5d, 0xa0, 0xa1, 0x2d, 0xe8, 0xa8, 0x8a, 0xe6, 0x84, 0xbe, 0x51, 0x83, + 0xa6, 0x3a, 0x51, 0xab, 0x64, 0xb8, 0x87, 0x83, 0xba, 0xc8, 0x98, 0x63, + 0x1a, 0xf6, 0x03, 0x18, 0xf0, 0x44, 0x9a, 0xc6, 0x5a, 0x52, 0x4c, 0xfe, + 0xe0, 0xa4, 0x5d, 0x50, 0x0e, 0xc6, 0x62, 0x81, 0x45, 0x67, 0x8b, 0xeb, + 0x52, 0x93, 0x64, 0xd4, 0x31, 0x00, 0x70, 0xd4, 0xb4, 0x25, 0xf3, 0x84, + 0x35, 0x97, 0xb3, 0x48, 0xa8, 0x34, 0x64, 0xdd, 0x16, 0x8d, 0x91, 0x2e, + 0x0a, 0x48, 0x37, 0x4c, 0xa9, 0x24, 0x98, 0x6c, 0x14, 0x85, 0x00, 0xee, + 0x46, 0x76, 0x62, 0xc9, 0x2a, 0x5d, 0x49, 0xad, 0x59, 0xcc, 0xed, 0x42, + 0xe9, 0x49, 0x62, 0xea, 0xf5, 0x05, 0x8d, 0xaf, 0x9c, 0xdd, 0xa9, 0x6b, + 0xf1, 0x6f, 0x0e, 0x63, 0x0d, 0xaa, 0x50, 0x55, 0xcb, 0x7c, 0x95, 0x1b, + 0x20, 0x7d, 0x51, 0xf2, 0xf7, 0x58, 0xae, 0x6b, 0xe7, 0xbd, 0xb0, 0x40, + 0xe9, 0x1f, 0x20, 0x43, 0xdb, 0x36, 0x7c, 0x95, 0x0e, 0x26, 0xd6, 0xec, + 0x25, 0x16, 0xc1, 0x5a, 0x72, 0xc4, 0x55, 0xfd, 0x25, 0xc1, 0x69, 0xff, + 0x00, 0x58, 0xe9, 0x30, 0x4c, 0xa3, 0x7f, 0x33, 0x69, 0x48, 0x52, 0x45, + 0xbb, 0x95, 0xdc, 0xb9, 0xea, 0x40, 0xb3, 0x47, 0xcd, 0x96, 0x68, 0xe5, + 0x23, 0x5e, 0x51, 0x07, 0x09, 0x99, 0x25, 0x0b, 0xb1, 0x49, 0x4c, 0x34, + 0x0d, 0xf0, 0x1a, 0xc2, 0xb8, 0x9b, 0x58, 0xeb, 0xd0, 0x13, 0x67, 0x35, + 0xce, 0x54, 0x55, 0x10, 0xa0, 0x1d, 0x32, 0x56, 0xed, 0xab, 0x80, 0xc5, + 0x42, 0xcd, 0xce, 0x43, 0x88, 0x06, 0x01, 0xc4, 0xc9, 0x8d, 0xd1, 0x06, + 0x0c, 0x98, 0xe9, 0x46, 0xad, 0x92, 0x8d, 0x60, 0x3c, 0x1d, 0xd2, 0x44, + 0xc3, 0x18, 0xd6, 0x3a, 0xc5, 0x0b, 0xe3, 0xc1, 0x12, 0x9b, 0x1a, 0x65, + 0x49, 0x73, 0xea, 0xc5, 0xcf, 0x2a, 0x80, 0x52, 0x0d, 0x25, 0xe8, 0x86, + 0x68, 0xed, 0xc8, 0xe2, 0xea, 0x48, 0x14, 0xf6, 0x80, 0x3d, 0x71, 0x5c, + 0xcd, 0x20, 0xba, 0x38, 0x43, 0x39, 0x6b, 0x14, 0x8a, 0x83, 0x36, 0x0d, + 0x91, 0x68, 0xd5, 0x12, 0xde, 0x4d, 0x06, 0xe9, 0x95, 0x24, 0xcb, 0xb3, + 0x41, 0x4a, 0x14, 0x8d, 0xf1, 0x1a, 0xc6, 0xb1, 0xee, 0x64, 0x2c, 0xb9, + 0x8a, 0x54, 0xbe, 0x91, 0x80, 0x21, 0x30, 0xb4, 0x0b, 0xa5, 0xa5, 0x4a, + 0x9e, 0xe5, 0x41, 0xa2, 0xb1, 0xce, 0x2e, 0x0f, 0x6d, 0xb0, 0x83, 0x85, + 0xce, 0x61, 0xb5, 0x48, 0x20, 0x16, 0x2d, 0xf2, 0x54, 0x6c, 0x91, 0xf5, + 0x47, 0x88, 0x47, 0xba, 0x45, 0x73, 0x5f, 0x3e, 0x0e, 0xc1, 0x03, 0xd6, + 0x1f, 0x20, 0x43, 0x9b, 0x31, 0x7c, 0x95, 0xab, 0xeb, 0x20, 0x0c, 0xc2, + 0x5d, 0x6e, 0x17, 0x68, 0x49, 0x91, 0x53, 0x0c, 0x29, 0xac, 0xbe, 0xe8, + 0x39, 0x26, 0x69, 0xf0, 0x90, 0x6c, 0xd5, 0x42, 0x8d, 0x0a, 0x0f, 0x73, + 0xae, 0xd1, 0xca, 0x65, 0x59, 0xb3, 0xa4, 0x55, 0x6e, 0xe1, 0x13, 0x85, + 0x24, 0x55, 0x15, 0x88, 0x29, 0xaa, 0x99, 0x83, 0x19, 0x4e, 0x43, 0x09, + 0x47, 0x60, 0x62, 0x69, 0x22, 0x54, 0x0c, 0x66, 0xc5, 0x50, 0x56, 0x97, + 0xaa, 0x70, 0xec, 0x89, 0x7b, 0x8b, 0xa6, 0xe7, 0xa6, 0xa0, 0x31, 0x80, + 0x9d, 0x49, 0x5a, 0x2a, 0x05, 0xd3, 0x54, 0xa1, 0x7a, 0x04, 0xb8, 0xb1, + 0x6c, 0x80, 0xe0, 0x8f, 0xdc, 0x3b, 0x20, 0x3d, 0xce, 0x52, 0x62, 0xbe, + 0x61, 0xd6, 0x28, 0x5f, 0xfe, 0xb5, 0xe2, 0x51, 0x63, 0x88, 0x01, 0xca, + 0xdd, 0x75, 0x41, 0x59, 0x8a, 0xc9, 0x87, 0x62, 0xca, 0xdb, 0x50, 0xa3, + 0xb5, 0x29, 0xbc, 0x53, 0x0a, 0x61, 0x98, 0xa2, 0x26, 0xa8, 0x5c, 0x2a, + 0x89, 0x74, 0xd0, 0xdd, 0x9b, 0x54, 0x8a, 0x83, 0x66, 0xa8, 0x24, 0xd9, + 0xba, 0x29, 0x85, 0x04, 0x49, 0x04, 0x08, 0x09, 0xa4, 0x99, 0x03, 0x11, + 0x48, 0x42, 0x94, 0xa5, 0x0d, 0x60, 0xee, 0x82, 0xcf, 0xd9, 0x25, 0x6d, + 0x33, 0xb1, 0xd0, 0x32, 0xaa, 0x5a, 0x85, 0xda, 0xf2, 0xa3, 0x56, 0xe4, + 0x95, 0x5f, 0xce, 0xa6, 0xa1, 0xd1, 0x69, 0xa8, 0xa9, 0xe7, 0xac, 0x66, + 0x8b, 0x6d, 0x31, 0x29, 0xdb, 0xb5, 0xc7, 0xf3, 0x70, 0xb7, 0xa8, 0xc7, + 0xdc, 0xe2, 0xa9, 0xb0, 0x8e, 0x14, 0xed, 0x17, 0x4a, 0x1b, 0xf7, 0xe1, + 0x5b, 0x28, 0x7c, 0x95, 0xac, 0xce, 0xc9, 0x40, 0xa7, 0x6f, 0x6e, 0x17, + 0x6d, 0xe4, 0xc9, 0x8d, 0x2d, 0x8a, 0x14, 0xd6, 0x5c, 0xfa, 0xa5, 0x2e, + 0xcd, 0x88, 0xe8, 0x83, 0x31, 0xbe, 0x5e, 0xe9, 0x3a, 0x4a, 0x14, 0xa7, + 0x4d, 0x42, 0x19, 0x35, 0x08, 0x60, 0xa4, 0xa7, 0x21, 0xc2, 0xd4, 0xc5, + 0x30, 0x0d, 0x42, 0x53, 0x14, 0x44, 0x04, 0x06, 0xf8, 0x43, 0xc6, 0x24, + 0x21, 0xbd, 0xcc, 0x76, 0x22, 0xf6, 0x54, 0xa0, 0x80, 0xda, 0x99, 0xa2, + 0xc6, 0x35, 0x09, 0x5b, 0x63, 0x3b, 0x63, 0x5b, 0x37, 0x3e, 0x31, 0x14, + 0xed, 0xe8, 0xa0, 0xe5, 0x81, 0x10, 0xc1, 0x1b, 0xd9, 0x23, 0x7b, 0x83, + 0x07, 0x78, 0xa2, 0x38, 0x5d, 0xca, 0x52, 0x8e, 0x00, 0x5d, 0x1f, 0x68, + 0x31, 0x6f, 0xde, 0x86, 0x12, 0x6b, 0x53, 0xfb, 0x98, 0xdc, 0x41, 0xf4, + 0xe9, 0x62, 0xd2, 0x00, 0x9c, 0xb9, 0x03, 0x16, 0xdd, 0x2b, 0x6d, 0x2a, + 0x8e, 0x8e, 0x24, 0x6a, 0x96, 0x30, 0x32, 0xb9, 0xa5, 0x16, 0xa9, 0x9a, + 0x84, 0xd0, 0x44, 0x85, 0x49, 0x14, 0x53, 0x22, 0x49, 0x26, 0x40, 0x02, + 0x91, 0x34, 0xd3, 0x28, 0x10, 0x84, 0x21, 0x42, 0xa2, 0x94, 0x85, 0x00, + 0x29, 0x40, 0x2a, 0x00, 0x0a, 0x3b, 0xa9, 0x61, 0x6e, 0x9d, 0xb4, 0xde, + 0x4e, 0x0a, 0x3e, 0x97, 0x08, 0x05, 0xda, 0xa5, 0x29, 0x7f, 0x4a, 0x69, + 0xae, 0x39, 0xba, 0x65, 0x03, 0x10, 0xb8, 0xd7, 0x49, 0x20, 0xc6, 0x30, + 0x62, 0x98, 0x3a, 0xa2, 0x62, 0x60, 0x10, 0xc7, 0xf0, 0x8b, 0xb7, 0x8c, + 0xb4, 0xe9, 0x80, 0xb0, 0x21, 0xad, 0xc6, 0x18, 0x87, 0x68, 0x43, 0xb9, + 0x29, 0x1c, 0x33, 0x5d, 0x1b, 0xf9, 0x4b, 0xbd, 0xe5, 0xa6, 0x12, 0x70, + 0xf5, 0x2b, 0x49, 0xe5, 0x90, 0x66, 0x53, 0x19, 0x95, 0xb0, 0x50, 0xa3, + 0x74, 0x84, 0xa3, 0x9c, 0x18, 0x0e, 0x30, 0xce, 0xc8, 0x9c, 0x54, 0x54, + 0x83, 0x59, 0x1d, 0x38, 0x5c, 0x83, 0x48, 0x10, 0xbd, 0xd8, 0xa4, 0xc9, + 0xa2, 0x56, 0xb2, 0x89, 0xf1, 0x8e, 0xed, 0xbd, 0xa8, 0x50, 0x9a, 0x0e, + 0xa9, 0xfd, 0x2d, 0xad, 0x55, 0x05, 0xa2, 0x86, 0xcd, 0x13, 0x28, 0x54, + 0x08, 0xac, 0x99, 0x74, 0xa3, 0x45, 0xb8, 0x5e, 0x1a, 0xf7, 0xb1, 0x87, + 0xc9, 0x30, 0xf0, 0x1b, 0x58, 0x9d, 0xc7, 0x6c, 0x38, 0x09, 0xd7, 0xb6, + 0x6c, 0x41, 0xf7, 0x8f, 0xfe, 0xc2, 0x0b, 0xba, 0x47, 0x34, 0x92, 0x58, + 0xe8, 0xa5, 0x32, 0x98, 0xdb, 0x96, 0x94, 0x97, 0x70, 0x06, 0x1f, 0x73, + 0xd8, 0x8e, 0x23, 0x66, 0xeb, 0x90, 0x55, 0x54, 0x86, 0xa4, 0xa6, 0x6c, + 0xd9, 0x72, 0x1b, 0x0c, 0xb4, 0xf7, 0x63, 0xe9, 0x39, 0xc0, 0xb9, 0xea, + 0xd7, 0x3c, 0xcb, 0x56, 0x35, 0x1d, 0x45, 0xfa, 0x25, 0x36, 0x65, 0x75, + 0xa5, 0x22, 0xc0, 0x26, 0x41, 0x51, 0xc4, 0x45, 0x04, 0xf4, 0x5b, 0x10, + 0xb0, 0xe5, 0x83, 0xa4, 0xcc, 0x8b, 0x96, 0xca, 0x9d, 0x15, 0x08, 0xa1, + 0x44, 0x0c, 0x9a, 0xa9, 0x98, 0x48, 0x62, 0x98, 0xa3, 0x5d, 0xfa, 0x4a, + 0x72, 0xeb, 0x52, 0x10, 0x20, 0x21, 0x47, 0xf5, 0x58, 0x6f, 0x6b, 0xe3, + 0x0a, 0x0d, 0x78, 0x43, 0xb8, 0x40, 0x85, 0x0a, 0x44, 0x6a, 0x08, 0x41, + 0xa3, 0x64, 0xce, 0xb3, 0x85, 0xd4, 0x22, 0x28, 0xa4, 0x99, 0x44, 0xca, + 0x2c, 0xba, 0xa6, 0x02, 0x14, 0x84, 0x28, 0x56, 0x63, 0x1c, 0xe6, 0x02, + 0x90, 0x02, 0xb1, 0x1a, 0x02, 0x18, 0xca, 0x84, 0x0a, 0x33, 0x15, 0x83, + 0x3f, 0x4e, 0x16, 0x2d, 0x79, 0xac, 0xc5, 0x72, 0x97, 0x34, 0x25, 0xb6, + 0x99, 0x36, 0xa4, 0x02, 0x35, 0x4b, 0x10, 0x95, 0x2c, 0xd2, 0x80, 0x32, + 0x86, 0xee, 0xe5, 0xec, 0xbe, 0xc7, 0xd0, 0xa6, 0x60, 0x99, 0x6d, 0xe6, + 0xec, 0x93, 0x0e, 0xcb, 0x4c, 0x81, 0x5b, 0xc4, 0x8a, 0x1f, 0xae, 0x21, + 0x43, 0xab, 0x80, 0x61, 0x87, 0x55, 0xc2, 0x05, 0x04, 0xc2, 0x02, 0x16, + 0x8a, 0x16, 0xa1, 0x03, 0x54, 0x34, 0x86, 0x23, 0x63, 0x01, 0x0c, 0x43, + 0xe5, 0x0a, 0xa2, 0xb2, 0x8f, 0xf5, 0xb3, 0x78, 0x77, 0x86, 0x2f, 0x71, + 0x7b, 0xed, 0xe1, 0xe0, 0x8b, 0x92, 0xf4, 0x6f, 0x8d, 0xe0, 0x8b, 0x61, + 0xad, 0x41, 0xbe, 0x3f, 0xca, 0x5f, 0xea, 0xb8, 0x4a, 0xcd, 0xec, 0x91, + 0xa1, 0x91, 0x39, 0x4b, 0x4d, 0x8e, 0xcb, 0xdc, 0x12, 0x83, 0x96, 0xdc, + 0xbd, 0xb6, 0x59, 0x33, 0x56, 0x41, 0xb5, 0x35, 0xab, 0x12, 0x9c, 0x00, + 0xd5, 0x99, 0xd5, 0x01, 0xfa, 0x31, 0xf5, 0x01, 0x49, 0x8c, 0x9b, 0x31, + 0x92, 0xce, 0x8d, 0x49, 0x8c, 0x62, 0x92, 0x86, 0x4e, 0xcd, 0x8f, 0x36, + 0x4d, 0x30, 0xea, 0x47, 0x1f, 0xf3, 0x13, 0x28, 0x80, 0x8e, 0x11, 0x29, + 0x11, 0x3c, 0x1b, 0x3f, 0xc9, 0x9c, 0x2e, 0xd8, 0x07, 0xb3, 0x59, 0x17, + 0x3d, 0x36, 0x10, 0xc4, 0x22, 0x74, 0xad, 0x80, 0x94, 0xf7, 0xaa, 0x5a, + 0x9b, 0xe0, 0xc7, 0x55, 0x68, 0x72, 0x0e, 0x3b, 0x64, 0x04, 0x07, 0x93, + 0x1d, 0x60, 0x7e, 0x8c, 0xdd, 0x11, 0xd6, 0x07, 0xe8, 0xcd, 0xd1, 0x1d, + 0x60, 0x7e, 0x8c, 0xdd, 0x11, 0xd6, 0x07, 0xe8, 0xcf, 0xd1, 0x1d, 0x60, + 0x7e, 0x8c, 0xdd, 0x11, 0xd6, 0x07, 0xe8, 0xcf, 0xd1, 0x1d, 0x60, 0x7e, + 0x8c, 0xfd, 0x11, 0xd6, 0x07, 0xe8, 0xcd, 0xd1, 0x1d, 0x60, 0x7e, 0x8c, + 0xdd, 0x11, 0xd6, 0x47, 0xe8, 0xcd, 0xd1, 0x1d, 0x60, 0x7e, 0x8c, 0xfd, + 0x11, 0xd6, 0x7f, 0x86, 0x6e, 0x88, 0xb8, 0x6c, 0x26, 0x36, 0x2b, 0x54, + 0x04, 0x47, 0x93, 0x09, 0xa7, 0x2e, 0xb1, 0xf7, 0xc9, 0xa2, 0x7f, 0xdb, + 0x5e, 0xa4, 0x66, 0x6c, 0x88, 0x5c, 0x66, 0x17, 0x0b, 0xda, 0x26, 0x34, + 0x05, 0xd5, 0xa1, 0x0c, 0x65, 0x4c, 0x18, 0x09, 0x98, 0x68, 0x08, 0x42, + 0x6f, 0x64, 0x6e, 0x13, 0x9f, 0x4d, 0x91, 0xb5, 0x51, 0x06, 0xc0, 0x9d, + 0x12, 0x96, 0x6b, 0x07, 0xeb, 0x00, 0x8a, 0x86, 0x68, 0xf9, 0x42, 0x0d, + 0x69, 0x1d, 0x72, 0x22, 0x91, 0x46, 0xeb, 0x3b, 0x0a, 0x85, 0x22, 0x85, + 0xd4, 0x2a, 0x5d, 0x4b, 0x98, 0xb9, 0x11, 0xaf, 0xab, 0xb4, 0x6e, 0xb7, + 0x9c, 0x4c, 0xd1, 0xda, 0x29, 0x3f, 0x8b, 0x19, 0x7b, 0x18, 0xed, 0x14, + 0x9f, 0xc5, 0x8c, 0xbd, 0x8c, 0x76, 0x8a, 0x4d, 0xe2, 0xc6, 0x5e, 0xc2, + 0x3b, 0x45, 0x26, 0xf1, 0x63, 0x2f, 0x61, 0x1d, 0xa2, 0x93, 0xf8, 0xb1, + 0x97, 0xb1, 0x8e, 0xd1, 0x49, 0xbc, 0x58, 0xcb, 0xd8, 0x47, 0x68, 0xa4, + 0xde, 0x2c, 0x65, 0xec, 0x23, 0xb4, 0x52, 0x6f, 0x16, 0x32, 0xf6, 0x11, + 0xda, 0x29, 0x37, 0x8a, 0xd9, 0x7b, 0x08, 0xed, 0x14, 0x9b, 0xc5, 0x8c, + 0xbd, 0x84, 0x76, 0x8a, 0x4d, 0xe2, 0xc6, 0x5e, 0xc2, 0x3b, 0x45, 0x26, + 0xf1, 0x63, 0x2f, 0x61, 0x00, 0xa3, 0x59, 0x64, 0xbd, 0xb2, 0x81, 0x78, + 0xed, 0xd9, 0x36, 0x44, 0xe1, 0xb4, 0x64, 0xd3, 0x28, 0x87, 0xfb, 0x17, + 0xff, 0xc4, 0x00, 0x2b, 0x10, 0x00, 0x01, 0x02, 0x03, 0x06, 0x05, 0x05, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x11, + 0x21, 0x31, 0xf0, 0x10, 0x41, 0x51, 0x61, 0x71, 0x81, 0x30, 0x91, 0xa1, + 0xb1, 0xc1, 0x20, 0x40, 0xd1, 0xe1, 0xf1, 0x50, 0x60, 0xff, 0xda, 0x00, + 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f, 0x21, 0xff, 0x00, 0x03, 0xfb, 0xc4, + 0x41, 0x30, 0x6a, 0x08, 0x55, 0x75, 0xb8, 0x0b, 0xa1, 0x23, 0xee, 0x87, + 0xae, 0x00, 0x77, 0x4e, 0x84, 0x83, 0xba, 0x74, 0x44, 0x5d, 0xd3, 0xa2, + 0x82, 0xee, 0x86, 0x58, 0xea, 0x1e, 0xf6, 0x0d, 0xf5, 0x7a, 0x1d, 0x92, + 0x9e, 0x03, 0x04, 0xea, 0x08, 0xbb, 0x27, 0x54, 0x65, 0xd9, 0x3a, 0xbc, + 0x2e, 0xc9, 0xd5, 0x48, 0x76, 0x4e, 0xa8, 0xcf, 0xb2, 0x0e, 0x80, 0x89, + 0xd8, 0xa0, 0x09, 0x90, 0x27, 0x40, 0xe9, 0xb9, 0x8b, 0x77, 0xb5, 0x7a, + 0x3d, 0xba, 0xd2, 0x22, 0xd9, 0x90, 0xd5, 0x7c, 0x4e, 0x95, 0xa0, 0x44, + 0x81, 0xd8, 0x3d, 0xab, 0x12, 0x56, 0x00, 0x22, 0x88, 0x01, 0x43, 0xb1, + 0x12, 0x17, 0x45, 0xbd, 0x16, 0x50, 0x4e, 0x84, 0xae, 0x03, 0x16, 0xcd, + 0xba, 0xf7, 0x4e, 0x6c, 0x1a, 0x66, 0x85, 0x1d, 0xd6, 0x81, 0x6e, 0x3b, + 0x32, 0x7d, 0xa4, 0xf8, 0x32, 0xdb, 0x65, 0x2f, 0x38, 0x90, 0x3b, 0xf4, + 0x00, 0x0b, 0x74, 0xa7, 0xfd, 0xff, 0x00, 0x4a, 0xdf, 0x53, 0xb4, 0xbe, + 0x43, 0x1d, 0xda, 0x65, 0xdd, 0xd1, 0x23, 0xb1, 0x5c, 0x7f, 0x55, 0xf7, + 0x4e, 0x44, 0x62, 0x55, 0x6b, 0xd6, 0x19, 0xef, 0x8e, 0x53, 0xa6, 0x06, + 0xd8, 0x23, 0x00, 0xad, 0x46, 0x15, 0x81, 0xb3, 0xf0, 0x28, 0x2b, 0xf1, + 0x2d, 0x3e, 0x2a, 0x27, 0xf5, 0xe4, 0xca, 0xb0, 0x89, 0x92, 0x71, 0x84, + 0xce, 0x63, 0xf2, 0x27, 0x58, 0xc2, 0xd4, 0xdb, 0xc4, 0xfc, 0xa0, 0x67, + 0xc8, 0x6f, 0x3c, 0x14, 0x5e, 0x42, 0xf3, 0x78, 0x93, 0x6f, 0x6a, 0xe9, + 0x0c, 0x97, 0x6e, 0xc9, 0x47, 0xc0, 0x8d, 0xcb, 0x44, 0x0e, 0xc3, 0x7d, + 0xd1, 0x45, 0xa6, 0x6e, 0x27, 0x9a, 0x25, 0xad, 0xd3, 0x43, 0x8e, 0x2c, + 0x18, 0x4e, 0x2a, 0x9f, 0xf7, 0x05, 0x59, 0x72, 0x66, 0x8e, 0x5d, 0xa2, + 0x30, 0x34, 0xb7, 0x1d, 0x80, 0x3b, 0x82, 0xba, 0xbf, 0x75, 0x6e, 0xf7, + 0x74, 0xcc, 0xd9, 0x01, 0xfc, 0xc8, 0x73, 0x4c, 0x5d, 0x53, 0xf3, 0xbc, + 0x99, 0x33, 0x6e, 0x61, 0xf6, 0xe8, 0x1b, 0x65, 0x14, 0x14, 0x1a, 0x08, + 0xde, 0x7a, 0xe6, 0xe0, 0x23, 0x1c, 0x94, 0x25, 0xc2, 0xe2, 0x46, 0xd0, + 0xe3, 0xb8, 0xa9, 0x59, 0x01, 0x1b, 0x23, 0x63, 0x30, 0x8d, 0x2c, 0x09, + 0x2c, 0x8b, 0x13, 0xc1, 0x82, 0xb0, 0xcc, 0x91, 0x60, 0xaf, 0x60, 0x30, + 0xc0, 0x10, 0x88, 0x14, 0x64, 0x92, 0x0b, 0xf9, 0x3c, 0x65, 0x23, 0x5f, + 0x08, 0x33, 0x0e, 0x08, 0x2f, 0x6e, 0x09, 0x92, 0x04, 0x19, 0x9c, 0x2b, + 0x9b, 0x2e, 0x3d, 0xd2, 0xde, 0x82, 0x3e, 0x59, 0xbf, 0xe2, 0x0a, 0x8c, + 0xe7, 0x61, 0xe1, 0x21, 0xd8, 0x8d, 0xc8, 0xc4, 0xdb, 0xaa, 0x1d, 0xcc, + 0x94, 0x1d, 0x84, 0x33, 0x9c, 0x8c, 0xf5, 0x2c, 0xd8, 0x92, 0x36, 0x51, + 0x1b, 0x11, 0x6c, 0xf0, 0xd9, 0x30, 0x5b, 0x65, 0x72, 0xeb, 0x76, 0x7d, + 0xe8, 0x53, 0xa2, 0x27, 0x8d, 0xe7, 0xf2, 0x6e, 0xe6, 0x81, 0x66, 0x56, + 0xc4, 0xdd, 0xd0, 0xb1, 0x12, 0xea, 0x5f, 0x28, 0x96, 0x7e, 0x73, 0xe5, + 0x1b, 0x12, 0x77, 0x45, 0x82, 0x34, 0x7f, 0x99, 0xa9, 0x49, 0xe3, 0x61, + 0x27, 0x39, 0xa8, 0xcb, 0x09, 0x00, 0x66, 0x1b, 0x9f, 0xa4, 0x19, 0x83, + 0xd1, 0x79, 0x41, 0x35, 0x76, 0xeb, 0x38, 0xe5, 0x45, 0xb2, 0x22, 0x48, + 0x1c, 0xb1, 0x23, 0x47, 0x5e, 0x89, 0xc2, 0x41, 0x27, 0x51, 0x25, 0x91, + 0xa3, 0x36, 0x90, 0x4f, 0x42, 0x0a, 0x94, 0xa5, 0x7f, 0x7a, 0x9f, 0xf7, + 0x4e, 0xee, 0xe8, 0x58, 0x0d, 0xaf, 0x01, 0x83, 0x3e, 0x13, 0xb8, 0x8e, + 0x89, 0xe7, 0x71, 0xc2, 0x74, 0x21, 0x03, 0x85, 0xc8, 0x78, 0xca, 0x72, + 0x1f, 0xe0, 0xae, 0x1a, 0xf0, 0x78, 0x73, 0x70, 0x19, 0xd3, 0x9a, 0x2e, + 0xee, 0x80, 0x74, 0x10, 0x66, 0x76, 0x5c, 0x99, 0x62, 0x1c, 0x71, 0x07, + 0x12, 0x47, 0x19, 0x3a, 0xa1, 0xde, 0x13, 0x51, 0x4a, 0x52, 0x22, 0xe3, + 0x0e, 0x2c, 0x00, 0xbb, 0x29, 0x07, 0x02, 0x11, 0xc6, 0x2c, 0x03, 0x16, + 0x53, 0xbc, 0xb3, 0x0c, 0xca, 0x27, 0xa4, 0x70, 0x61, 0xf8, 0x94, 0x02, + 0x62, 0x44, 0x02, 0x40, 0x03, 0x6b, 0xfe, 0x39, 0xb5, 0xc4, 0x45, 0xd0, + 0x1c, 0x1b, 0x32, 0xd8, 0xc5, 0xcf, 0x29, 0xeb, 0xd7, 0xca, 0x72, 0xf7, + 0xde, 0xa3, 0xa7, 0x97, 0x9b, 0x21, 0x89, 0x88, 0xb8, 0xc2, 0x09, 0xf2, + 0xdb, 0xa7, 0xc2, 0xc2, 0x7c, 0xb2, 0x53, 0xc4, 0xa9, 0x09, 0x57, 0xd2, + 0x82, 0x21, 0x17, 0x95, 0xd4, 0x5a, 0xe4, 0x0b, 0x0c, 0x33, 0x3a, 0x7e, + 0xf2, 0x2a, 0xe2, 0x71, 0x89, 0xbe, 0xfa, 0xd1, 0x18, 0xc5, 0x7d, 0x4a, + 0xea, 0x82, 0x05, 0x83, 0x44, 0x7a, 0x42, 0xaf, 0xec, 0xd8, 0x46, 0x46, + 0x01, 0x08, 0x14, 0x0c, 0xb1, 0x4d, 0x9c, 0x3b, 0xab, 0xa9, 0xca, 0x34, + 0x65, 0x09, 0x94, 0xfd, 0x11, 0x43, 0xae, 0x29, 0xc4, 0xa8, 0xa7, 0x37, + 0x4b, 0x06, 0xa9, 0xa8, 0x0b, 0x03, 0x70, 0x70, 0xca, 0x98, 0x61, 0xc2, + 0xce, 0xd9, 0x39, 0xc9, 0x94, 0x69, 0x38, 0x78, 0xce, 0x58, 0x45, 0x1c, + 0x59, 0x58, 0x76, 0xab, 0x83, 0xb3, 0x04, 0xba, 0xa2, 0x19, 0x7a, 0xc3, + 0xcf, 0x14, 0x71, 0x0c, 0x66, 0x99, 0xba, 0x17, 0xb6, 0x48, 0xe9, 0xc5, + 0x31, 0x89, 0x33, 0x63, 0x31, 0x2d, 0x5e, 0x41, 0x42, 0x8c, 0x9e, 0xb1, + 0x7e, 0xf2, 0xde, 0x48, 0xbb, 0xc4, 0xa0, 0xfb, 0xe3, 0xa7, 0x94, 0xfd, + 0xb1, 0x86, 0xbc, 0xd7, 0xdc, 0x25, 0x1a, 0xc5, 0x66, 0xff, 0x00, 0x19, + 0xf3, 0xfc, 0x57, 0x76, 0xf2, 0x9a, 0xe8, 0xc9, 0xf7, 0xce, 0xbb, 0xaa, + 0xc2, 0x7d, 0x94, 0x7a, 0x51, 0x0a, 0x34, 0xd5, 0x7c, 0x79, 0x68, 0x32, + 0x39, 0x46, 0xaf, 0xf9, 0x5d, 0x98, 0x57, 0x39, 0x20, 0x70, 0xad, 0xd1, + 0xcb, 0xcf, 0xd5, 0x81, 0x31, 0x47, 0x15, 0x29, 0x73, 0xed, 0xac, 0x25, + 0x22, 0xc9, 0xfb, 0x20, 0x5c, 0x29, 0x8b, 0x84, 0x2e, 0xae, 0x6a, 0xec, + 0x72, 0xc3, 0x74, 0x0c, 0xb7, 0x9a, 0x9c, 0x95, 0xf1, 0x8a, 0x81, 0x11, + 0x28, 0x33, 0x10, 0x64, 0x9c, 0xf7, 0x58, 0x41, 0x17, 0x91, 0xbd, 0x4b, + 0xe5, 0x40, 0x5f, 0xdd, 0x06, 0x3c, 0x43, 0xef, 0x01, 0x20, 0x0b, 0xc9, + 0xf2, 0x6e, 0x15, 0x01, 0x32, 0x67, 0x04, 0x48, 0xc0, 0x11, 0x48, 0x1f, + 0x96, 0xff, 0x00, 0x5c, 0xbf, 0x1b, 0xe2, 0x7b, 0x36, 0x88, 0x63, 0xf8, + 0xb0, 0xdd, 0xd2, 0x5b, 0x47, 0xac, 0x91, 0x0f, 0x1f, 0x1d, 0xb5, 0xba, + 0xef, 0x20, 0x8d, 0xaa, 0xbb, 0xac, 0xc7, 0xc5, 0x6b, 0x43, 0xa4, 0x58, + 0xe7, 0xd6, 0x78, 0xba, 0xf9, 0xc3, 0x92, 0x10, 0xcc, 0xdc, 0xa3, 0x2e, + 0x72, 0x72, 0xa2, 0xf8, 0x67, 0x97, 0xea, 0xef, 0xa7, 0x48, 0x68, 0xaa, + 0xa7, 0x7e, 0x2a, 0x67, 0x02, 0x81, 0x6a, 0xe6, 0xb1, 0x56, 0x68, 0xfc, + 0x5f, 0x41, 0x12, 0x94, 0x7a, 0xa2, 0x1d, 0x51, 0x41, 0x44, 0x1e, 0x85, + 0xc9, 0x19, 0x61, 0xe8, 0x38, 0x01, 0x32, 0x79, 0x2a, 0x92, 0x11, 0x08, + 0x36, 0x05, 0xf9, 0xee, 0x8a, 0xae, 0xcd, 0x3d, 0xc6, 0x53, 0x64, 0x6a, + 0xf5, 0x72, 0x7e, 0xf7, 0x57, 0xd2, 0x77, 0xd2, 0xbe, 0x11, 0x9a, 0x7c, + 0x99, 0xfd, 0x83, 0x38, 0x9a, 0xea, 0x1d, 0x61, 0x46, 0xa8, 0x11, 0xb2, + 0x23, 0x1c, 0xfd, 0x66, 0x94, 0x29, 0xcb, 0x9e, 0xf8, 0x57, 0xef, 0x45, + 0x3a, 0x99, 0xf2, 0xa7, 0x1d, 0x03, 0x29, 0x78, 0xc2, 0xa4, 0x72, 0x29, + 0xf5, 0xc7, 0x24, 0x72, 0x84, 0x91, 0xeb, 0x88, 0xad, 0x94, 0x0e, 0xba, + 0xf2, 0x44, 0x9e, 0x53, 0xcd, 0x4d, 0xfa, 0xaa, 0xfc, 0x52, 0xbb, 0xe9, + 0x66, 0x83, 0xb6, 0x6b, 0xa6, 0xca, 0xab, 0xfc, 0xa2, 0xe8, 0x8d, 0x7c, + 0x1b, 0xdb, 0x4f, 0xb6, 0x2a, 0x45, 0xb9, 0x2d, 0x32, 0xc5, 0x72, 0xac, + 0x1d, 0xd0, 0x6b, 0xd3, 0xa8, 0xd8, 0x32, 0xb2, 0x17, 0x9d, 0x2c, 0x85, + 0x63, 0x14, 0xe0, 0x1c, 0x93, 0xaf, 0xb6, 0xa8, 0xfd, 0x6d, 0x4b, 0x26, + 0xbc, 0xcd, 0x0e, 0x0d, 0x7f, 0x9c, 0x7e, 0x54, 0x6f, 0x1d, 0x6b, 0xca, + 0xfd, 0x9a, 0x8c, 0x5e, 0xb6, 0xa0, 0xab, 0xaa, 0xa7, 0x59, 0x20, 0x49, + 0x73, 0x5c, 0xf7, 0x35, 0x05, 0xbb, 0x55, 0x66, 0x9d, 0xc5, 0x55, 0xec, + 0xaa, 0xfa, 0xb9, 0x66, 0x82, 0xcd, 0x34, 0xc2, 0xa2, 0xfb, 0x22, 0x43, + 0x14, 0x62, 0xe8, 0xa3, 0x3b, 0x09, 0x76, 0xe4, 0x15, 0x2d, 0x6f, 0x23, + 0x0a, 0x7e, 0x15, 0x7d, 0xfe, 0x27, 0x65, 0xe5, 0x48, 0xd9, 0x05, 0xdd, + 0x67, 0x8a, 0x8c, 0x94, 0x78, 0x22, 0x8b, 0x1b, 0x25, 0x8c, 0x45, 0x0e, + 0x96, 0xec, 0xf4, 0x6a, 0x6e, 0xaa, 0x3b, 0x2a, 0xf7, 0x76, 0x93, 0x28, + 0xb4, 0xef, 0x89, 0x3a, 0xa7, 0x7e, 0x48, 0x38, 0xf9, 0xf8, 0x75, 0xca, + 0xb0, 0x6f, 0xb4, 0xe0, 0x19, 0xad, 0x50, 0xfd, 0x32, 0xef, 0xf4, 0x86, + 0xbc, 0xf9, 0xa7, 0xbe, 0xab, 0xe9, 0x76, 0x8c, 0x2a, 0xa2, 0xa1, 0xa5, + 0x4e, 0x6b, 0xe5, 0x4c, 0xcd, 0x01, 0x24, 0x2e, 0x22, 0x98, 0x7b, 0x03, + 0x44, 0xb8, 0x8d, 0xec, 0xa5, 0x6b, 0xe8, 0x7a, 0x5a, 0xfc, 0x2d, 0xe0, + 0x54, 0x93, 0xa1, 0x3b, 0x82, 0x38, 0x2d, 0x13, 0xa7, 0xa6, 0xfc, 0x57, + 0xad, 0x10, 0xc9, 0x62, 0x7e, 0x35, 0xf5, 0xff, 0x00, 0x02, 0xff, 0x00, + 0x75, 0xc0, 0xcd, 0x24, 0xdf, 0x77, 0x49, 0xf4, 0x42, 0x55, 0x5d, 0xd7, + 0xe3, 0xdc, 0x6a, 0x6d, 0x24, 0xd9, 0xb4, 0x95, 0x77, 0xe5, 0x05, 0xce, + 0xba, 0xc5, 0x0d, 0x1b, 0xe3, 0xbe, 0x29, 0xd8, 0x6d, 0xb7, 0x7f, 0x0f, + 0xad, 0xe1, 0xf6, 0x69, 0x47, 0xca, 0xbe, 0xb7, 0xad, 0x11, 0x66, 0x86, + 0x55, 0xb2, 0xef, 0x55, 0x7c, 0x97, 0x8d, 0x3a, 0x2b, 0xe3, 0xa0, 0xf3, + 0xd1, 0x0a, 0xaf, 0xa4, 0xe9, 0xbb, 0xa3, 0x88, 0xa8, 0xa2, 0x6b, 0x60, + 0xde, 0xa4, 0x88, 0x08, 0xb0, 0x29, 0x7a, 0x35, 0x30, 0x64, 0xe1, 0x5f, + 0x97, 0xa6, 0x09, 0x96, 0xea, 0xec, 0xd0, 0x4e, 0xa7, 0x92, 0x1f, 0x05, + 0x0e, 0x00, 0xe0, 0xcd, 0x42, 0xae, 0x5a, 0xb9, 0x15, 0xd1, 0x64, 0xbb, + 0xcf, 0xe1, 0x7c, 0x06, 0xd7, 0xc6, 0xcb, 0x72, 0xda, 0xf9, 0xba, 0x9d, + 0x17, 0x83, 0x34, 0x39, 0xd4, 0x55, 0x6c, 0xf0, 0x4f, 0x1c, 0x41, 0x57, + 0xb8, 0xe7, 0x9f, 0xc5, 0xeb, 0x1f, 0x3d, 0x14, 0x3e, 0x6e, 0x9d, 0x54, + 0x14, 0x8d, 0xc0, 0x41, 0x4e, 0xbe, 0x6e, 0x40, 0x9e, 0xdd, 0x51, 0x36, + 0x95, 0x51, 0x45, 0xb5, 0x64, 0x86, 0xf3, 0x24, 0x58, 0x3e, 0x94, 0xe8, + 0x94, 0x7e, 0xf6, 0x86, 0x7a, 0x65, 0x39, 0x15, 0x29, 0x48, 0x5b, 0x77, + 0xe0, 0xa4, 0xa2, 0xb2, 0x17, 0x7a, 0xc2, 0x91, 0x77, 0xa9, 0x1b, 0x0e, + 0x09, 0xbb, 0x1d, 0x2c, 0x8a, 0xf8, 0x4e, 0xd7, 0x1a, 0xcd, 0x55, 0x60, + 0x9f, 0xb4, 0x68, 0x2b, 0xe8, 0x2e, 0xd2, 0x8c, 0x32, 0x52, 0xe8, 0xe6, + 0xa7, 0xa6, 0xdb, 0xb1, 0x1d, 0x4a, 0x6e, 0xa5, 0x65, 0x4e, 0x65, 0x9f, + 0x0e, 0x07, 0x3d, 0x8c, 0x38, 0x18, 0x92, 0x05, 0x48, 0x13, 0x5b, 0x92, + 0xa6, 0x22, 0x01, 0x56, 0x80, 0x9e, 0x21, 0x8a, 0x81, 0xa6, 0xd5, 0x66, + 0xc8, 0xa6, 0x4a, 0x67, 0x09, 0x82, 0x9d, 0x0c, 0x94, 0x79, 0xa4, 0x16, + 0x69, 0x01, 0x4e, 0x2f, 0x3d, 0x12, 0x6b, 0x38, 0x9b, 0x22, 0xbc, 0x59, + 0x07, 0x50, 0x4c, 0x7c, 0x07, 0xe9, 0xcd, 0xd1, 0xf4, 0xad, 0x83, 0x8a, + 0xd9, 0x5d, 0x3a, 0xaf, 0xa4, 0x7b, 0xeb, 0x97, 0x3e, 0x88, 0xf4, 0xa9, + 0xe0, 0x13, 0xc3, 0x11, 0xf3, 0xfc, 0x17, 0xb4, 0x96, 0x34, 0xca, 0xe5, + 0xcf, 0x81, 0x2f, 0xae, 0x28, 0xcf, 0xca, 0x21, 0xa3, 0x89, 0x10, 0x55, + 0x7d, 0x64, 0xaa, 0xb7, 0x4f, 0x55, 0x9e, 0x2b, 0x6e, 0x7f, 0xc4, 0x9f, + 0xe0, 0x07, 0xc2, 0x47, 0x13, 0x9f, 0x6b, 0x5f, 0x99, 0x5d, 0x18, 0xce, + 0xaf, 0x0a, 0xa1, 0x3b, 0x95, 0x57, 0xda, 0x87, 0x4b, 0xf0, 0x4f, 0x87, + 0xd7, 0xef, 0xbf, 0x7e, 0x7d, 0x97, 0x7b, 0x33, 0xb0, 0xd7, 0x07, 0xeb, + 0x58, 0x9b, 0x19, 0x21, 0xba, 0x5a, 0x42, 0xaf, 0xc0, 0xa8, 0xee, 0xa8, + 0x79, 0x8a, 0x35, 0xd2, 0x8a, 0x94, 0xeb, 0x5f, 0xe0, 0x47, 0x9f, 0xa3, + 0x33, 0xc1, 0xf5, 0xf3, 0x2f, 0xd2, 0x45, 0xf3, 0xbb, 0x94, 0x3e, 0x54, + 0x58, 0x63, 0x55, 0xe5, 0x39, 0xd5, 0x39, 0x8e, 0xdc, 0x98, 0x78, 0xfd, + 0xf7, 0xee, 0xf6, 0x08, 0x5b, 0x4b, 0x82, 0xcf, 0x80, 0x3a, 0x6a, 0x5e, + 0x15, 0xe7, 0xa6, 0xea, 0x40, 0x02, 0x8d, 0xd3, 0x53, 0xeb, 0xa8, 0xae, + 0x4a, 0xfa, 0xca, 0xbb, 0x7f, 0x00, 0x0c, 0xc9, 0xec, 0xf2, 0xa3, 0x98, + 0x39, 0x6c, 0xb2, 0xe0, 0x05, 0x5b, 0xb3, 0x76, 0xb2, 0x63, 0xde, 0xb2, + 0x9a, 0xc8, 0xd7, 0xec, 0x57, 0xcb, 0x64, 0x61, 0xd9, 0x4f, 0x2f, 0x7e, + 0x14, 0x0a, 0x05, 0xe6, 0xb4, 0x4e, 0xf9, 0x22, 0xd0, 0xaa, 0x3d, 0x91, + 0xbf, 0x00, 0x01, 0xa7, 0x7f, 0xf9, 0xeb, 0x65, 0x50, 0x58, 0x57, 0x35, + 0x0a, 0xda, 0xc0, 0x4c, 0xbc, 0xf9, 0xfe, 0x0e, 0x04, 0x06, 0xc3, 0x9c, + 0x1e, 0xe4, 0x45, 0x90, 0x59, 0x7c, 0xb0, 0x4f, 0x74, 0xbe, 0x7f, 0x11, + 0xde, 0xee, 0x9e, 0x56, 0x4e, 0x2a, 0xe4, 0x2e, 0xce, 0xed, 0x7f, 0x82, + 0x78, 0xa8, 0x52, 0xa6, 0x82, 0x5f, 0xb8, 0x34, 0x46, 0x4d, 0xee, 0xaa, + 0x3f, 0x16, 0x74, 0x6b, 0xc4, 0x13, 0x92, 0xe3, 0xa1, 0x0a, 0xf3, 0xcb, + 0x5a, 0xf2, 0x9a, 0xaa, 0xb3, 0x58, 0x50, 0xac, 0x7f, 0x80, 0x93, 0xd0, + 0x83, 0x89, 0xc1, 0xf1, 0xfe, 0x02, 0x92, 0xe2, 0x83, 0x8e, 0x42, 0xb7, + 0x4f, 0x2f, 0xd2, 0x7e, 0x94, 0xbe, 0x25, 0x9a, 0xdb, 0x44, 0xd9, 0x7f, + 0x01, 0x8a, 0x86, 0x04, 0x19, 0x7d, 0x89, 0xbe, 0x57, 0x03, 0x83, 0x92, + 0xe8, 0xf7, 0xc4, 0x83, 0x57, 0x49, 0xef, 0x75, 0xde, 0xbf, 0x51, 0x6f, + 0x8f, 0x1f, 0x68, 0xe9, 0xbd, 0x49, 0x45, 0xa3, 0xcd, 0xf4, 0xd7, 0xdf, + 0x99, 0x67, 0x4e, 0xc0, 0x58, 0x3d, 0x96, 0x6a, 0xf4, 0xe0, 0xec, 0xed, + 0x44, 0xd8, 0x47, 0xe5, 0x5e, 0x25, 0x5e, 0x54, 0x80, 0xbf, 0x25, 0x11, + 0xf1, 0x15, 0xd1, 0x9b, 0xab, 0xfb, 0xf1, 0x05, 0x9c, 0x54, 0x02, 0xe4, + 0x0a, 0x3e, 0x08, 0x6d, 0x0f, 0xe4, 0x71, 0x20, 0xae, 0xf7, 0xd3, 0xce, + 0xc7, 0xe9, 0x4e, 0x6b, 0xe5, 0x73, 0xc7, 0xc4, 0x13, 0xc2, 0xbc, 0x7f, + 0x03, 0xcc, 0xb0, 0x88, 0x86, 0xf4, 0x7c, 0x14, 0xfa, 0xed, 0x2a, 0xd6, + 0x81, 0x91, 0xe6, 0x9d, 0xa4, 0x9e, 0x07, 0xb5, 0xca, 0x81, 0xf3, 0xf4, + 0xaa, 0xe9, 0xff, 0x00, 0x02, 0xae, 0x9d, 0x39, 0x60, 0x01, 0x13, 0xe8, + 0x07, 0x81, 0x19, 0x35, 0xa4, 0x56, 0x65, 0x5d, 0x57, 0x6f, 0x3f, 0x5f, + 0x61, 0x3c, 0x54, 0xbf, 0x81, 0x0d, 0x78, 0xd0, 0x28, 0x39, 0x12, 0x58, + 0xfd, 0x79, 0x96, 0x8a, 0xe2, 0x7a, 0x18, 0x14, 0x96, 0xf5, 0xf7, 0xfc, + 0x3a, 0xe5, 0x6e, 0x2c, 0x54, 0x14, 0xdd, 0xde, 0x27, 0x35, 0xd9, 0x0a, + 0xeb, 0x1b, 0xdf, 0x82, 0xd8, 0x18, 0xac, 0x49, 0xeb, 0x7e, 0xde, 0x07, + 0xb2, 0x55, 0xd2, 0x70, 0xfa, 0x2b, 0xe3, 0xf8, 0x23, 0xb7, 0xd8, 0x3f, + 0x60, 0x7e, 0x61, 0x45, 0x0b, 0x3b, 0x81, 0x43, 0xaa, 0xe0, 0xfe, 0x21, + 0x3b, 0x26, 0x08, 0x59, 0xe9, 0xb4, 0xc4, 0xd1, 0x3a, 0x70, 0xfd, 0x7a, + 0x9b, 0x2a, 0x66, 0xa7, 0xf0, 0xff, 0x00, 0x8c, 0x8d, 0xa7, 0x22, 0xf6, + 0x04, 0xf9, 0x6a, 0x0b, 0x80, 0xea, 0xae, 0xc7, 0xe5, 0x47, 0xb5, 0x9a, + 0x7d, 0xeb, 0x65, 0x42, 0xaa, 0x3e, 0xfd, 0x96, 0xd9, 0x1e, 0xab, 0xe6, + 0xc2, 0x38, 0x8d, 0x99, 0x2f, 0xc5, 0x97, 0xec, 0xa2, 0xeb, 0x1d, 0xbf, + 0x81, 0xf8, 0x58, 0x49, 0x75, 0x7c, 0x99, 0x8a, 0x79, 0x5f, 0x55, 0xa2, + 0x7c, 0x03, 0x15, 0x1c, 0x15, 0xf3, 0x64, 0x6d, 0xae, 0xbe, 0xfc, 0x66, + 0x57, 0x28, 0x95, 0x6f, 0x60, 0x5a, 0x9c, 0x1c, 0x98, 0x96, 0xbd, 0x26, + 0x27, 0x55, 0x55, 0xb5, 0xb5, 0x5b, 0x7b, 0xf2, 0x80, 0x47, 0xb5, 0x88, + 0xb0, 0x93, 0xf0, 0x4d, 0x04, 0x96, 0x9b, 0x87, 0xed, 0x77, 0x57, 0xaf, + 0x85, 0x55, 0x82, 0xcf, 0xdf, 0x8c, 0x28, 0x62, 0x52, 0x10, 0xab, 0xf5, + 0x44, 0x4f, 0x65, 0x70, 0x5f, 0x14, 0xf3, 0xac, 0x87, 0xa0, 0x75, 0xfe, + 0x03, 0x1c, 0xf6, 0xe4, 0x9c, 0xbe, 0xfb, 0x42, 0xf9, 0x17, 0x02, 0xbd, + 0x64, 0xaf, 0x9c, 0xc6, 0x8e, 0xf6, 0x55, 0x54, 0x97, 0xe7, 0xf0, 0x7a, + 0x14, 0x54, 0xaa, 0xaa, 0x75, 0x81, 0xa2, 0x06, 0x21, 0x49, 0x46, 0xf9, + 0x6f, 0x70, 0x75, 0x69, 0xdb, 0x75, 0x27, 0x4b, 0x3c, 0xff, 0x00, 0x84, + 0x12, 0x06, 0x8b, 0xb2, 0x89, 0x04, 0x73, 0x20, 0xb4, 0xea, 0x89, 0x73, + 0x16, 0xd4, 0x67, 0x43, 0xf5, 0xd2, 0xc0, 0xdc, 0xbb, 0xd6, 0x84, 0x7b, + 0x47, 0x8a, 0xb9, 0x65, 0xdf, 0xf8, 0x51, 0x35, 0x14, 0x53, 0x44, 0xd3, + 0x4d, 0x44, 0x93, 0x49, 0x25, 0x14, 0x4d, 0x34, 0xd3, 0x4d, 0x34, 0xd3, + 0x4d, 0x24, 0xd3, 0x51, 0x28, 0x0a, 0x06, 0x9d, 0x03, 0x04, 0x68, 0x14, + 0x50, 0x30, 0xe7, 0x80, 0xb5, 0x12, 0x70, 0x87, 0x6f, 0xd9, 0xeb, 0x61, + 0x10, 0x09, 0xcc, 0x63, 0x92, 0x18, 0xf9, 0x8d, 0x95, 0x95, 0x5e, 0x55, + 0x6e, 0xab, 0x3e, 0x1f, 0xdf, 0xa9, 0xfd, 0x38, 0x70, 0x01, 0x64, 0x56, + 0x05, 0x60, 0x0d, 0x88, 0x33, 0x70, 0x8e, 0x59, 0xcd, 0xba, 0x22, 0x35, + 0x40, 0x91, 0xcc, 0x38, 0xea, 0xe5, 0xeb, 0x34, 0xb0, 0x7d, 0xb7, 0x31, + 0xda, 0x84, 0x0b, 0xdd, 0x82, 0x61, 0x8d, 0xe5, 0xa4, 0x55, 0x8a, 0x3e, + 0x89, 0x70, 0x65, 0xc0, 0x3c, 0x4b, 0xd0, 0x28, 0x14, 0x68, 0x1b, 0x0b, + 0x8d, 0x13, 0x83, 0xf3, 0xbf, 0xd3, 0x9c, 0x8a, 0x29, 0x11, 0x4c, 0x03, + 0xb1, 0x5b, 0xfa, 0xe2, 0x32, 0x58, 0x88, 0xbf, 0xf3, 0x9c, 0x86, 0x03, + 0xb9, 0x6f, 0x7c, 0xc8, 0x8e, 0xa7, 0x85, 0x57, 0xd7, 0x1c, 0x70, 0x7e, + 0xec, 0x04, 0xa0, 0x6c, 0x01, 0x44, 0xd7, 0xc1, 0x69, 0x78, 0x34, 0x51, + 0x39, 0xed, 0x0a, 0x6c, 0x63, 0x4e, 0xf0, 0xc1, 0x74, 0x4d, 0xe4, 0xfa, + 0xcb, 0x77, 0x38, 0x33, 0x76, 0x67, 0xe4, 0x8f, 0xb8, 0xc3, 0x85, 0xf0, + 0x8f, 0xb5, 0xbf, 0x7c, 0x0c, 0x7d, 0x06, 0xef, 0x40, 0x28, 0x14, 0x0f, + 0xc7, 0x44, 0x02, 0xf2, 0x8b, 0x3c, 0x8f, 0x70, 0x1c, 0xea, 0x55, 0x40, + 0xc8, 0xe7, 0x08, 0x61, 0x37, 0x01, 0xdf, 0xd7, 0x1f, 0x84, 0x3c, 0x03, + 0x38, 0x20, 0x40, 0x48, 0x20, 0xc0, 0x88, 0x22, 0x00, 0x53, 0x51, 0x34, + 0x61, 0x70, 0x53, 0xbc, 0x2f, 0x29, 0x8a, 0x46, 0x6f, 0x78, 0x0e, 0x84, + 0x31, 0x1a, 0xfb, 0xab, 0x94, 0x7d, 0x5d, 0x7d, 0x00, 0xa1, 0x81, 0x76, + 0x1d, 0x02, 0x23, 0xb8, 0x76, 0x3a, 0x79, 0x67, 0x22, 0x44, 0x24, 0x18, + 0xe2, 0xb9, 0xc4, 0x04, 0xc3, 0x82, 0x00, 0x01, 0x80, 0x10, 0x00, 0x08, + 0x00, 0x20, 0x07, 0x01, 0xd6, 0x7e, 0x10, 0x60, 0x64, 0xd8, 0x30, 0xce, + 0xaf, 0xe0, 0x54, 0x16, 0x19, 0xdd, 0x77, 0x7b, 0x62, 0xb7, 0x7b, 0xaa, + 0xa8, 0xfa, 0xea, 0xae, 0xb0, 0xad, 0x77, 0x41, 0x12, 0x6b, 0x2e, 0x4f, + 0x63, 0x9a, 0xc5, 0x7c, 0x08, 0x91, 0x14, 0x68, 0x70, 0x22, 0xaf, 0x10, + 0x38, 0xe3, 0x81, 0xd8, 0xe0, 0x4f, 0x10, 0x46, 0x2c, 0xc0, 0x8c, 0x03, + 0xc8, 0x66, 0x02, 0x18, 0xc3, 0x91, 0xba, 0x5c, 0x80, 0x63, 0xf6, 0x9a, + 0xfb, 0xb6, 0xb3, 0xf4, 0x3e, 0x1e, 0x8a, 0xaa, 0x9a, 0xfb, 0x5d, 0xbd, + 0x15, 0x55, 0xb2, 0x05, 0x30, 0x46, 0xbc, 0xcd, 0xb3, 0xd5, 0x07, 0x20, + 0x53, 0x6d, 0x94, 0x88, 0x74, 0xe3, 0x76, 0x5f, 0x32, 0x78, 0x22, 0xd0, + 0x40, 0x8b, 0x84, 0x40, 0x9d, 0xa0, 0x48, 0x14, 0x67, 0x53, 0xb7, 0x18, + 0x71, 0x91, 0x15, 0x30, 0xe2, 0xf1, 0x25, 0x7c, 0xe0, 0x0b, 0x13, 0xa8, + 0x4b, 0xdd, 0xfe, 0x2d, 0x54, 0x14, 0x6c, 0xae, 0x7e, 0x9c, 0x67, 0x83, + 0x0e, 0xd4, 0x17, 0x20, 0x84, 0x96, 0x2c, 0x48, 0x9c, 0xb9, 0x89, 0xf6, + 0xc1, 0x70, 0x2e, 0x21, 0x84, 0x08, 0x70, 0xc4, 0x01, 0x5a, 0x00, 0x03, + 0x84, 0x41, 0x7d, 0x47, 0x24, 0xe6, 0x0f, 0x79, 0x40, 0x32, 0x28, 0xa1, + 0xc3, 0xc8, 0xef, 0x23, 0xc6, 0x55, 0x56, 0x96, 0x37, 0x07, 0x1c, 0x3d, + 0x1d, 0xb8, 0x11, 0x41, 0x83, 0x88, 0x44, 0x8c, 0x04, 0x7c, 0x19, 0x9c, + 0xc5, 0x42, 0x07, 0x38, 0x50, 0x8a, 0x48, 0x5e, 0x8e, 0x1e, 0x0d, 0x41, + 0x80, 0xdb, 0x00, 0x4b, 0xc4, 0x01, 0x35, 0xc1, 0x2a, 0x6c, 0x44, 0x80, + 0x09, 0x79, 0x74, 0x1c, 0x4a, 0x20, 0x58, 0xba, 0x02, 0x79, 0x33, 0x11, + 0x88, 0xd8, 0x83, 0xc6, 0x7f, 0x4e, 0x96, 0xd5, 0x7c, 0xdb, 0x55, 0x5d, + 0x7d, 0x35, 0x57, 0xd9, 0xb5, 0xa2, 0x4c, 0x86, 0x49, 0x90, 0xc6, 0xe5, + 0x97, 0x32, 0x79, 0x68, 0xd6, 0x02, 0x3c, 0x81, 0x16, 0x75, 0x07, 0xcb, + 0xf4, 0x72, 0x70, 0x98, 0x0a, 0x8c, 0xd7, 0x40, 0x71, 0x1a, 0x30, 0xc3, + 0x58, 0xb4, 0xb0, 0x13, 0x0e, 0x61, 0xa0, 0xe9, 0x33, 0x96, 0x03, 0xe0, + 0x1d, 0x1e, 0xf2, 0xed, 0xdc, 0x5d, 0x2d, 0xbe, 0xca, 0xd2, 0xda, 0xaa, + 0x87, 0xa6, 0xab, 0x6e, 0x0b, 0x98, 0x9c, 0x20, 0x1e, 0x45, 0xfe, 0x8b, + 0x24, 0x84, 0x65, 0xc1, 0x8e, 0x08, 0xd8, 0x26, 0x06, 0x1d, 0x83, 0x07, + 0x8b, 0x80, 0x36, 0x1c, 0x70, 0xe1, 0x22, 0xd7, 0xa4, 0x28, 0x4d, 0x22, + 0x41, 0x09, 0xb2, 0x02, 0x33, 0x80, 0x26, 0x26, 0x0c, 0x40, 0xba, 0x69, + 0x7b, 0xfa, 0xaf, 0x2a, 0xb9, 0xfc, 0xd8, 0xd5, 0xaa, 0x7d, 0x89, 0x86, + 0x46, 0x80, 0x08, 0x92, 0x10, 0x44, 0xc8, 0x84, 0xd4, 0x52, 0x10, 0x8c, + 0x06, 0x77, 0xae, 0x70, 0x78, 0x12, 0x2f, 0x71, 0x45, 0x23, 0xd9, 0x46, + 0xa4, 0x9e, 0x43, 0x00, 0xe4, 0xc1, 0x40, 0x86, 0xd2, 0x81, 0x2d, 0x28, + 0x3c, 0xb5, 0xc5, 0x07, 0x0b, 0x97, 0x02, 0x4f, 0xe8, 0xac, 0x2c, 0xf1, + 0xe8, 0x3e, 0x99, 0xf0, 0xd0, 0x89, 0x2e, 0xdb, 0x0b, 0xd0, 0x84, 0xcc, + 0x77, 0x89, 0x8c, 0x41, 0x7d, 0x94, 0x75, 0xa2, 0x6e, 0x31, 0xe6, 0x9a, + 0xe4, 0x20, 0xd8, 0x13, 0x07, 0x20, 0xa0, 0x02, 0x01, 0x38, 0xb1, 0x1d, + 0x8d, 0x48, 0xe4, 0x71, 0x53, 0xb2, 0xaa, 0xff, 0x00, 0x55, 0x57, 0x9b, + 0x39, 0x7b, 0x61, 0x94, 0x0c, 0x18, 0xf3, 0x0d, 0xee, 0xb7, 0x1a, 0x75, + 0x6b, 0x37, 0x54, 0x77, 0x01, 0xca, 0x04, 0x4a, 0x0b, 0x8e, 0x04, 0xc1, + 0x10, 0x00, 0x01, 0x88, 0x0c, 0x08, 0x22, 0x04, 0x18, 0x10, 0x82, 0x8c, + 0xcf, 0x10, 0x7e, 0x42, 0xd3, 0x45, 0x12, 0x22, 0x83, 0x47, 0x31, 0xde, + 0xc9, 0x03, 0x37, 0xf2, 0x57, 0xd2, 0xe9, 0xe9, 0xaa, 0xa7, 0xf4, 0x55, + 0x6f, 0xec, 0xf6, 0xaa, 0xfd, 0x4e, 0x08, 0x71, 0x3c, 0x8c, 0x86, 0xf6, + 0xca, 0x51, 0xda, 0xd0, 0xfa, 0x28, 0xe9, 0x3b, 0x00, 0x61, 0xc5, 0x84, + 0x1b, 0xea, 0x00, 0xd8, 0x0f, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0d, + 0xec, 0x09, 0x3d, 0x47, 0xad, 0x5a, 0x19, 0x32, 0x38, 0x16, 0x1d, 0x01, + 0x1c, 0x78, 0xec, 0x4c, 0x9c, 0x31, 0xe8, 0x0f, 0x42, 0xb6, 0x5a, 0x7a, + 0xb5, 0xf6, 0x83, 0x1d, 0x68, 0x43, 0x85, 0x68, 0x98, 0x59, 0x60, 0x8e, + 0x60, 0x41, 0x86, 0x4c, 0xc3, 0x28, 0x5e, 0xc5, 0xfc, 0xb6, 0xba, 0x08, + 0xa1, 0x78, 0x28, 0x81, 0x0c, 0x20, 0x8e, 0xcb, 0xc7, 0xcd, 0xc6, 0x47, + 0x55, 0xc9, 0x14, 0xcb, 0xb3, 0xc4, 0x73, 0x47, 0xca, 0x2b, 0x9c, 0x5a, + 0xaa, 0xc6, 0xc3, 0xee, 0x0a, 0x06, 0x4f, 0x1a, 0xb7, 0x28, 0x06, 0xcc, + 0x40, 0x74, 0xd6, 0xa0, 0xbb, 0xb7, 0x0f, 0xaf, 0x53, 0xd7, 0x5a, 0xe2, + 0xb0, 0x92, 0xed, 0x29, 0xf6, 0x15, 0xb8, 0x1e, 0xc8, 0xd0, 0x6f, 0xc7, + 0xc1, 0x60, 0x41, 0x62, 0x8d, 0xc6, 0x91, 0x08, 0x03, 0x5d, 0x54, 0xf9, + 0x5f, 0x20, 0x4b, 0xbd, 0xe5, 0x3a, 0x10, 0xf3, 0x3a, 0x1d, 0x71, 0xfc, + 0x2f, 0x98, 0x25, 0xe8, 0xef, 0x34, 0xc0, 0xce, 0x41, 0x7c, 0x07, 0x87, + 0x02, 0x59, 0xa3, 0x7b, 0x20, 0x60, 0x70, 0x5f, 0x25, 0xa5, 0xc4, 0x22, + 0x1d, 0xc3, 0x10, 0x13, 0x51, 0x0a, 0xd4, 0x07, 0x34, 0x1c, 0x5b, 0x2f, + 0x01, 0xd8, 0x2c, 0xe4, 0x86, 0x34, 0x77, 0x8a, 0x39, 0xb8, 0xf7, 0x79, + 0xe9, 0xcc, 0x18, 0xed, 0x49, 0x89, 0x60, 0x8c, 0x04, 0x5c, 0x29, 0xae, + 0x83, 0x01, 0xc4, 0x05, 0xd0, 0x80, 0xcd, 0x1e, 0xed, 0x95, 0x1a, 0xf9, + 0x31, 0x2c, 0xe4, 0x93, 0xed, 0x23, 0x80, 0xa6, 0xb7, 0x42, 0x02, 0x5d, + 0x20, 0x10, 0x06, 0x05, 0x98, 0x04, 0x30, 0xcd, 0xe4, 0x81, 0xdd, 0xe4, + 0x46, 0xef, 0x76, 0x10, 0x66, 0x78, 0x3f, 0x52, 0x76, 0xf9, 0x62, 0x22, + 0xb7, 0x8c, 0x36, 0xc4, 0xa1, 0x8e, 0x20, 0xf0, 0x01, 0x0f, 0x13, 0xed, + 0x27, 0x48, 0xf5, 0x80, 0x78, 0x82, 0x06, 0x48, 0xc0, 0x01, 0x50, 0x42, + 0x5b, 0x41, 0x18, 0xc9, 0x3c, 0x5e, 0x06, 0x23, 0x31, 0x63, 0xf6, 0x11, + 0x63, 0xdc, 0x0b, 0x8b, 0xbd, 0x85, 0x7e, 0xaa, 0xaa, 0xeb, 0xe9, 0xaa, + 0xa6, 0xb6, 0x12, 0xdd, 0x68, 0x6d, 0x49, 0x89, 0x60, 0x81, 0x7b, 0x6a, + 0x6c, 0x12, 0xc0, 0xec, 0xd4, 0x10, 0x86, 0x66, 0x47, 0x12, 0xe2, 0x07, + 0x79, 0x3a, 0x33, 0x46, 0x24, 0x3e, 0xda, 0x01, 0x3a, 0x5d, 0x3d, 0x2c, + 0x44, 0xa5, 0xc0, 0x1a, 0x15, 0x90, 0x47, 0xa1, 0x48, 0x9c, 0xa3, 0xdd, + 0xc0, 0x8b, 0xbd, 0xc8, 0x03, 0xd8, 0x06, 0x2d, 0xc0, 0xd0, 0x7d, 0x18, + 0x9a, 0x70, 0x5a, 0x05, 0x97, 0x11, 0x6c, 0x23, 0x28, 0x20, 0x88, 0x86, + 0xde, 0xdb, 0x00, 0xfe, 0x42, 0x9a, 0x61, 0x5b, 0xc8, 0x8a, 0x07, 0xca, + 0x4d, 0x18, 0x40, 0x80, 0x4a, 0xf7, 0x8c, 0x1e, 0xa3, 0xa9, 0x85, 0xc8, + 0xe2, 0x8b, 0x99, 0x80, 0x7a, 0x1d, 0xbd, 0xb6, 0x08, 0x03, 0x77, 0x16, + 0x59, 0xa3, 0xd6, 0xe1, 0x98, 0x23, 0xb4, 0x43, 0x0f, 0x22, 0x22, 0x14, + 0x8e, 0x43, 0x22, 0xe4, 0xc2, 0xb1, 0x9c, 0xfa, 0xf4, 0x00, 0xf7, 0x17, + 0xd2, 0xad, 0xca, 0xbc, 0x98, 0xe3, 0x94, 0x58, 0x06, 0x50, 0x1a, 0x87, + 0x09, 0x43, 0x12, 0x1c, 0x49, 0x60, 0x01, 0x32, 0xf0, 0x50, 0x24, 0x06, + 0x04, 0x12, 0xf5, 0x86, 0x93, 0x19, 0x7b, 0x5a, 0xe8, 0x86, 0x30, 0xc1, + 0x1b, 0xdc, 0xe2, 0x6e, 0xea, 0x01, 0x92, 0x33, 0x67, 0xd5, 0x92, 0x7c, + 0x90, 0x44, 0xb9, 0x00, 0x17, 0xdc, 0x83, 0xdb, 0x86, 0x3a, 0xbb, 0xc1, + 0x06, 0x10, 0x42, 0x0c, 0x0a, 0x75, 0x78, 0xdc, 0x26, 0x5d, 0xa3, 0xb6, + 0x10, 0x60, 0x79, 0x60, 0x39, 0x09, 0x7e, 0x99, 0xe0, 0x0a, 0x38, 0xfb, + 0x56, 0x01, 0xc9, 0x1e, 0x86, 0xef, 0x23, 0x9b, 0x8a, 0x12, 0x84, 0x0a, + 0x48, 0xa0, 0x00, 0x31, 0x63, 0x06, 0x7a, 0xa6, 0x1e, 0xb8, 0x3e, 0x50, + 0xc0, 0x05, 0x88, 0x02, 0x00, 0xc3, 0xdd, 0x45, 0xdc, 0x8b, 0x3c, 0x43, + 0x02, 0x00, 0xda, 0x20, 0xec, 0x1f, 0x29, 0xd8, 0x03, 0x9c, 0x42, 0x35, + 0xe6, 0xb8, 0x03, 0xcc, 0x91, 0x4a, 0xb6, 0x61, 0x26, 0x01, 0x04, 0x8b, + 0x80, 0x46, 0x44, 0x70, 0x7b, 0xf0, 0xab, 0x34, 0x06, 0x78, 0x62, 0x04, + 0x5c, 0x8e, 0x80, 0xc7, 0x36, 0x24, 0x4b, 0xc1, 0x0b, 0x5c, 0xed, 0x99, + 0x78, 0x06, 0x23, 0x2f, 0xbb, 0x9d, 0x45, 0xa7, 0x40, 0x40, 0xc0, 0xda, + 0x10, 0x00, 0x44, 0x95, 0xa1, 0x5c, 0xe0, 0x69, 0x02, 0x3b, 0x51, 0x02, + 0xf2, 0x30, 0x03, 0xb6, 0x55, 0x46, 0xda, 0xaa, 0x7f, 0x45, 0x63, 0x61, + 0xb2, 0xbf, 0x7d, 0x50, 0x4e, 0x41, 0xbc, 0xba, 0x93, 0x48, 0xc9, 0x90, + 0x26, 0x09, 0x47, 0x2f, 0x0e, 0x5d, 0xa0, 0x88, 0x92, 0x7b, 0xd0, 0x29, + 0x71, 0x30, 0x80, 0xe0, 0x8d, 0x8a, 0x10, 0x0e, 0x13, 0x06, 0x5f, 0x0b, + 0xc6, 0xd1, 0x02, 0x03, 0x93, 0x23, 0xa3, 0x34, 0x88, 0xb0, 0x31, 0x62, + 0xf3, 0x6f, 0x32, 0x64, 0x8e, 0x02, 0xa3, 0x68, 0x55, 0x92, 0xae, 0xde, + 0x87, 0xfd, 0x38, 0x15, 0x00, 0x26, 0x4c, 0x80, 0x74, 0x0b, 0x13, 0x30, + 0x7c, 0x48, 0xbd, 0x12, 0x20, 0x71, 0x65, 0x05, 0x2d, 0xb8, 0x89, 0xc4, + 0x33, 0x6b, 0x0d, 0x37, 0x07, 0xde, 0xbc, 0x69, 0x7b, 0x44, 0x49, 0x38, + 0x91, 0xc2, 0x8a, 0xf1, 0xce, 0x84, 0x19, 0x0b, 0x4c, 0xef, 0x06, 0x4b, + 0x39, 0x04, 0x1d, 0xc6, 0x01, 0xa3, 0xc0, 0x91, 0x03, 0xa4, 0x5a, 0x44, + 0x38, 0x80, 0x88, 0xa6, 0x43, 0x5b, 0x5c, 0xd4, 0x6d, 0xe6, 0xaa, 0xa0, + 0x9b, 0x2b, 0x63, 0x85, 0x6c, 0xb0, 0xf9, 0xef, 0x8a, 0xd9, 0x15, 0x63, + 0x1c, 0x4d, 0xce, 0xa1, 0x91, 0x20, 0xb4, 0x81, 0x92, 0x21, 0x28, 0x11, + 0x82, 0x24, 0xf7, 0x33, 0x8b, 0x44, 0xcf, 0x20, 0x82, 0xc4, 0x0d, 0xe8, + 0x68, 0x34, 0x6c, 0x28, 0x4a, 0x44, 0xf7, 0xe5, 0xde, 0x13, 0xb7, 0xd1, + 0x23, 0xa4, 0xb8, 0x97, 0xa4, 0x4a, 0x20, 0x82, 0xc9, 0x81, 0x4f, 0xcc, + 0xf4, 0xb7, 0x49, 0x8a, 0x12, 0x44, 0xc0, 0x27, 0x13, 0x35, 0xc2, 0x9e, + 0x8f, 0x28, 0x76, 0x53, 0xe4, 0x1e, 0x80, 0x17, 0x18, 0x5d, 0xc3, 0x23, + 0xd2, 0x44, 0x8b, 0xae, 0x4c, 0xde, 0xfe, 0x55, 0x05, 0x07, 0x86, 0x02, + 0x13, 0x94, 0xdc, 0x91, 0x29, 0x88, 0x78, 0x17, 0x10, 0x77, 0xfe, 0x2d, + 0x06, 0x52, 0xb8, 0x52, 0x2b, 0x58, 0x86, 0x60, 0x9c, 0xa4, 0xef, 0xe1, + 0xfe, 0x32, 0x48, 0x87, 0x13, 0x84, 0xe2, 0x49, 0x04, 0xe7, 0xc5, 0x12, + 0x3f, 0x36, 0x6d, 0xfd, 0xbb, 0x76, 0x25, 0xd8, 0xb1, 0x6a, 0x41, 0xee, + 0x08, 0xa8, 0x1f, 0xf0, 0xbf, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x8d, 0x9d, 0xa6, 0xd3, + 0x6e, 0xd2, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0xde, + 0xf5, 0x5e, 0x01, 0x16, 0x10, 0x01, 0x24, 0x18, 0x48, 0x03, 0x8f, 0x44, + 0xc0, 0x60, 0x00, 0x00, 0x00, 0xb8, 0x06, 0x59, 0xc0, 0x35, 0x20, 0x08, + 0x00, 0x92, 0x49, 0x64, 0x12, 0x40, 0x04, 0x80, 0x90, 0x00, 0x00, 0x21, + 0x01, 0xa4, 0xc8, 0x20, 0x92, 0x09, 0x04, 0x90, 0x48, 0x04, 0x12, 0x48, + 0x00, 0x10, 0x4e, 0xf8, 0x00, 0x01, 0x24, 0x92, 0x40, 0x00, 0x92, 0x48, + 0x00, 0x00, 0x08, 0x24, 0x00, 0x00, 0x00, 0x80, 0x01, 0x05, 0x80, 0x00, + 0x06, 0x90, 0x48, 0x20, 0x02, 0x00, 0x20, 0x10, 0x08, 0x24, 0x12, 0x49, + 0x24, 0x90, 0x49, 0x20, 0x16, 0x00, 0x00, 0x16, 0x08, 0x26, 0x02, 0x41, + 0x60, 0x00, 0x00, 0x04, 0x92, 0x01, 0x04, 0x10, 0x41, 0x00, 0x90, 0x4e, + 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x24, 0x82, 0x48, 0x04, 0x92, 0x01, + 0x20, 0x00, 0x48, 0x24, 0x90, 0x40, 0x08, 0x00, 0x01, 0x04, 0x02, 0x01, + 0x2c, 0x80, 0x49, 0x00, 0x90, 0x08, 0x00, 0x02, 0x40, 0x04, 0x80, 0x48, + 0x00, 0xa0, 0x00, 0x05, 0x10, 0x08, 0x24, 0x12, 0x41, 0x00, 0x80, 0x01, + 0x00, 0x02, 0x41, 0x00, 0x02, 0x09, 0x00, 0x94, 0x80, 0x00, 0x14, 0x00, + 0x20, 0x92, 0x49, 0x24, 0x40, 0x08, 0x04, 0x02, 0x48, 0x00, 0x82, 0x01, + 0x20, 0x82, 0x02, 0x00, 0x00, 0x49, 0x00, 0x90, 0x08, 0x04, 0x02, 0x08, + 0x00, 0x02, 0x41, 0x20, 0x12, 0x48, 0x24, 0x12, 0x09, 0x48, 0x00, 0x00, + 0x00, 0x90, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x48, 0x00, 0x60, 0x00, 0x04, 0x90, 0x49, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x13, 0x80, + 0x00, 0x06, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x24, 0x80, 0x1e, 0x00, 0x00, 0x51, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x50, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x05, 0x40, 0x00, 0x00, 0x92, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x03, 0x80, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x01, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x40, 0x08, 0x00, 0x00, 0x24, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x20, 0x00, + 0x00, 0x02, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x04, 0x82, 0x00, 0x00, 0x02, 0x49, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x58, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x48, 0x10, 0x00, 0x00, 0x04, 0x12, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, + 0x24, 0xc0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x24, 0x05, 0x00, 0x00, 0x02, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x48, 0x00, 0x00, 0x00, 0x24, 0x90, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x41, 0x00, 0x00, 0x00, + 0x20, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x40, 0x00, 0x40, 0x00, 0x04, 0x82, 0x49, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x97, 0x00, + 0x00, 0x14, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x40, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x25, 0x20, 0x00, 0x00, 0x82, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x20, 0x00, 0x00, 0x00, 0x04, 0x40, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x91, 0x42, 0x00, 0x00, 0x01, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x48, 0x28, 0x00, 0x00, 0x40, 0x12, 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x14, 0xa0, 0x00, + 0x05, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x09, 0x00, 0x00, 0x80, 0x00, 0x10, 0x09, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x90, 0x4a, + 0x00, 0x00, 0x01, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x08, 0xa8, 0x00, 0x00, 0x00, 0x80, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x49, + 0x04, 0xc0, 0x00, 0x01, 0x90, 0x4a, 0x24, 0x92, 0x49, 0x24, 0x00, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x24, 0x00, 0x80, 0x00, 0x1a, 0x40, + 0x20, 0x12, 0x08, 0x20, 0x00, 0x41, 0x04, 0x92, 0x40, 0x04, 0x12, 0x08, + 0x20, 0x00, 0x46, 0x00, 0x00, 0x38, 0x2c, 0x00, 0x01, 0x20, 0x92, 0x48, + 0x24, 0x92, 0x01, 0x04, 0x02, 0x49, 0x20, 0x92, 0x49, 0x18, 0x00, 0x00, + 0x00, 0x12, 0x09, 0x00, 0x10, 0x01, 0x20, 0x00, 0x41, 0x04, 0x82, 0x49, + 0x04, 0x90, 0x40, 0x04, 0x20, 0x00, 0x03, 0x90, 0x00, 0x24, 0x92, 0x49, + 0x20, 0x80, 0x41, 0x04, 0x82, 0x48, 0x04, 0x82, 0x49, 0x24, 0x93, 0x00, + 0x00, 0x13, 0x88, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x04, 0x90, 0x01, + 0x20, 0x10, 0x00, 0x04, 0x80, 0x70, 0x00, 0x00, 0x06, 0x20, 0x00, 0x08, + 0x00, 0x12, 0x00, 0x20, 0x10, 0x48, 0x0c, 0x12, 0x09, 0x20, 0x80, 0x01, + 0x40, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x24, 0x10, 0x00, 0x24, 0x02, 0x08, + 0x04, 0xa2, 0x08, 0x01, 0x02, 0x48, 0x03, 0x00, 0x00, 0x00, 0x14, 0x08, + 0x00, 0x92, 0x49, 0x24, 0x80, 0x00, 0x04, 0x80, 0x41, 0x04, 0x82, 0x09, + 0x00, 0xb0, 0x00, 0x00, 0x00, 0x18, 0x20, 0x00, 0x48, 0x24, 0x80, 0x01, + 0x00, 0x92, 0x49, 0x04, 0x90, 0x48, 0x24, 0x02, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x02, 0x48, 0x00, 0x10, 0x40, 0x04, 0x00, 0x08, 0x04, 0x82, 0x01, + 0x24, 0x12, 0x34, 0x00, 0x00, 0x00, 0x00, 0x32, 0x49, 0x00, 0x02, 0x09, + 0x00, 0x10, 0x09, 0x04, 0x80, 0x40, 0x20, 0x90, 0x49, 0x40, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x20, 0x82, 0x40, 0x04, 0x82, 0x08, 0x04, 0x80, 0x40, + 0x00, 0x10, 0x49, 0x25, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x49, + 0x24, 0x00, 0x40, 0x24, 0x92, 0x08, 0x24, 0x02, 0x41, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x06, 0x82, 0x00, 0x04, 0x90, 0x00, 0x04, 0x02, 0x01, + 0x20, 0x10, 0x00, 0x40, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x12, 0xc9, + 0x04, 0x10, 0x40, 0x24, 0x02, 0x49, 0x20, 0x92, 0x01, 0x20, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x01, 0x24, 0x12, 0x01, + 0x24, 0x82, 0x08, 0x00, 0x00, 0x41, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x82, 0x01, 0x24, 0x12, 0x08, 0x24, 0x00, 0x41, 0x04, 0x12, 0x01, + 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x09, 0x24, 0x82, 0x49, + 0x20, 0x00, 0x00, 0x20, 0x92, 0x41, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x27, 0x24, 0x12, 0x48, 0x00, 0x02, 0x00, 0x04, 0x90, 0x49, + 0x24, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x08, + 0x24, 0x00, 0x48, 0x20, 0x82, 0x49, 0x24, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x04, 0x02, 0x00, 0x00, 0x10, 0x09, + 0x20, 0x02, 0x0a, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, + 0x24, 0x90, 0x49, 0x24, 0x92, 0x49, 0x20, 0x80, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0x12, 0x49, 0x00, 0x12, 0x00, + 0x00, 0x90, 0x41, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x1a, 0x01, 0x00, 0x90, 0x09, 0x20, 0x00, 0x08, 0x04, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x02, 0x00, + 0x04, 0x82, 0x48, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x14, 0x92, 0x48, 0x20, 0x80, 0x49, 0x00, 0x92, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x41, + 0x24, 0x90, 0x49, 0x00, 0x82, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x15, 0x20, 0x00, 0x09, 0x00, 0x80, 0x48, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x34, 0x92, 0x48, 0x20, 0x82, 0x41, 0x20, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xbf, 0x49, 0x30, 0xc1, 0x40, + 0x32, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0xb6, 0x59, 0x25, 0x96, 0xd4, 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, 0x3f, 0xff, 0xc4, + 0x00, 0x2b, 0x11, 0x00, 0x01, 0x01, 0x04, 0x08, 0x07, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xf0, 0x00, 0x11, 0x21, + 0x31, 0x20, 0x41, 0x51, 0x61, 0x71, 0x81, 0xa1, 0xd1, 0x30, 0x40, 0x50, + 0x91, 0xb1, 0xc1, 0xf1, 0x10, 0xe1, 0x60, 0xff, 0xda, 0x00, 0x08, 0x01, + 0x03, 0x01, 0x01, 0x3f, 0x10, 0xff, 0x00, 0x00, 0xf1, 0x6f, 0xe5, 0xc1, + 0xec, 0x5b, 0xee, 0x36, 0x6f, 0xb8, 0xd9, 0xbe, 0xf3, 0x66, 0x46, 0x7a, + 0x64, 0x37, 0xa6, 0x42, 0x7a, 0x64, 0x67, 0xa6, 0x42, 0x7a, 0x64, 0x27, + 0xa6, 0x43, 0x7a, 0x64, 0x27, 0xa6, 0x46, 0x7a, 0x6f, 0xbc, 0xd9, 0xbe, + 0xe3, 0x66, 0xfb, 0x8d, 0x9b, 0xee, 0x36, 0x62, 0x09, 0x90, 0xae, 0x20, + 0xca, 0xd6, 0x71, 0x13, 0x1c, 0xac, 0xdc, 0xc1, 0x21, 0x89, 0x2e, 0x03, + 0xbb, 0x10, 0x20, 0x83, 0x60, 0x0f, 0xd5, 0xe3, 0xc1, 0x60, 0x09, 0x92, + 0xc4, 0x81, 0xd9, 0xc0, 0x63, 0x17, 0xb5, 0xe0, 0xa2, 0xa2, 0x07, 0x76, + 0xbb, 0xf7, 0x3b, 0xb7, 0xca, 0x0c, 0xa4, 0xf4, 0xc0, 0x15, 0x18, 0x01, + 0xb3, 0x38, 0x58, 0x3b, 0x34, 0x70, 0x51, 0xb1, 0x4f, 0x89, 0xda, 0xfb, + 0x94, 0x3b, 0xf0, 0x17, 0x86, 0x73, 0xe6, 0xe3, 0x97, 0xd6, 0x79, 0x32, + 0x64, 0x18, 0x96, 0x67, 0xc4, 0x36, 0x6b, 0xb5, 0xf3, 0x70, 0x0e, 0xee, + 0xc5, 0xbe, 0x36, 0xcb, 0x46, 0x27, 0xf5, 0x04, 0x8f, 0x04, 0x0f, 0x4d, + 0x26, 0x20, 0x88, 0xc4, 0x8c, 0xf5, 0x63, 0x76, 0xa9, 0x08, 0x2d, 0xb0, + 0x87, 0xb1, 0xb7, 0x96, 0x95, 0x1c, 0x24, 0xf9, 0x88, 0xca, 0x37, 0xd9, + 0x3e, 0x11, 0x09, 0xe6, 0x02, 0x80, 0x7b, 0x39, 0x08, 0xc8, 0x03, 0x80, + 0x00, 0x2a, 0x1a, 0xfe, 0x7f, 0x55, 0xa8, 0xdd, 0x47, 0x33, 0xa6, 0xdf, + 0xba, 0xbb, 0x5f, 0x03, 0xd3, 0x59, 0xad, 0xec, 0x52, 0x73, 0xda, 0xb1, + 0x10, 0xfb, 0x20, 0xf7, 0x3a, 0xac, 0xc0, 0x3c, 0x5c, 0x90, 0x97, 0xf1, + 0xab, 0x67, 0x25, 0x8d, 0x0b, 0x61, 0x35, 0xfc, 0x43, 0xf5, 0x29, 0x32, + 0x4f, 0x64, 0xa2, 0xbc, 0xb4, 0x08, 0x71, 0x71, 0x07, 0x30, 0x5a, 0xfb, + 0x0c, 0x43, 0xe6, 0x36, 0x5d, 0x9c, 0x0c, 0x24, 0xee, 0x01, 0x84, 0x13, + 0x27, 0xb5, 0x64, 0xe4, 0x22, 0xc0, 0x00, 0x38, 0x00, 0x22, 0xec, 0x27, + 0x17, 0xd7, 0x6f, 0xf1, 0xbf, 0xac, 0x97, 0x6f, 0x2e, 0x6d, 0xe3, 0xda, + 0xaf, 0x3d, 0xda, 0x1e, 0xb0, 0x7f, 0x87, 0xb3, 0x9d, 0x25, 0x21, 0xe1, + 0xac, 0xf9, 0xa1, 0xfb, 0xfa, 0x8f, 0x36, 0x93, 0xbf, 0x12, 0x50, 0xfc, + 0xb5, 0x3c, 0xe3, 0xd9, 0x88, 0x00, 0x41, 0x0f, 0x04, 0x38, 0x83, 0x61, + 0x63, 0x9c, 0xa8, 0xc0, 0xda, 0x26, 0x0e, 0x63, 0x6a, 0x6f, 0x2c, 0x00, + 0x0c, 0xc9, 0xfe, 0x6b, 0x85, 0x04, 0x95, 0x5c, 0x14, 0xa6, 0xf4, 0x39, + 0xdc, 0xab, 0x44, 0xe2, 0xef, 0x02, 0xa6, 0x07, 0x39, 0x4c, 0x81, 0x38, + 0xa1, 0x0b, 0x6d, 0x6c, 0x29, 0x84, 0x6b, 0x5c, 0xec, 0x06, 0xfc, 0x04, + 0xbf, 0x9f, 0x89, 0x7f, 0x7a, 0x05, 0xb8, 0xf6, 0x97, 0xda, 0x98, 0x22, + 0x58, 0x43, 0xb8, 0x7f, 0xaa, 0x7a, 0xaf, 0x81, 0x45, 0x16, 0x5d, 0x96, + 0xd4, 0x85, 0xce, 0xcb, 0x9f, 0xd0, 0x69, 0x89, 0x2e, 0x19, 0xac, 0x59, + 0x27, 0x7e, 0xac, 0x28, 0xae, 0xd4, 0xa7, 0x78, 0x3c, 0xdf, 0xf1, 0xb4, + 0x1a, 0x62, 0x5b, 0x86, 0x6b, 0x1e, 0x0c, 0x0a, 0xb1, 0x43, 0x4a, 0x49, + 0x7c, 0x1c, 0xe6, 0x83, 0x1c, 0x93, 0x2a, 0x7a, 0xaf, 0x80, 0xa7, 0xda, + 0xb6, 0x5e, 0x3f, 0x52, 0x5f, 0xdf, 0xcd, 0x14, 0xbf, 0x52, 0x50, 0xa4, + 0xb0, 0xb9, 0x6d, 0xcc, 0xdb, 0x39, 0xec, 0x52, 0x0d, 0x98, 0x77, 0xb3, + 0xbf, 0x87, 0xd3, 0xd5, 0x7c, 0x0a, 0xd3, 0xb3, 0xe1, 0x4f, 0x80, 0x87, + 0x31, 0x6a, 0x5f, 0x1b, 0x41, 0xf1, 0x4d, 0x9a, 0xd8, 0x3f, 0xbc, 0x25, + 0xe3, 0xa0, 0x5b, 0x0a, 0xfb, 0xc0, 0x45, 0x58, 0xda, 0x0d, 0x31, 0x0c, + 0x25, 0xab, 0xf9, 0x41, 0x25, 0xfc, 0x69, 0x74, 0x5d, 0x07, 0xc5, 0x32, + 0x58, 0x48, 0x4a, 0xfb, 0x72, 0xa0, 0x97, 0xf3, 0xa3, 0xc9, 0x5d, 0xd0, + 0x6e, 0xa7, 0xaa, 0xc3, 0x21, 0xe7, 0xd3, 0x4b, 0xa4, 0xba, 0x77, 0x97, + 0xe8, 0x07, 0xa6, 0x91, 0x85, 0x0a, 0xac, 0xa9, 0x6a, 0x3e, 0x28, 0xa6, + 0x97, 0x7e, 0x8b, 0x6d, 0xc7, 0xfb, 0xed, 0xb6, 0x1c, 0x9e, 0xd7, 0xcc, + 0x69, 0xcd, 0x61, 0xae, 0xc1, 0x95, 0x7b, 0xd5, 0xd2, 0xb7, 0xf5, 0xae, + 0x7e, 0x9e, 0xc9, 0x2e, 0x35, 0x27, 0x67, 0x4d, 0x25, 0xc3, 0xf5, 0x0e, + 0x8f, 0x6e, 0x89, 0x63, 0x50, 0xd1, 0x7c, 0x54, 0x4e, 0xce, 0x9c, 0x93, + 0xe3, 0x1b, 0xae, 0x75, 0xc5, 0x74, 0xfa, 0x56, 0xeb, 0xbc, 0x7b, 0xb6, + 0x8b, 0xe2, 0xa2, 0x76, 0x74, 0xd2, 0x5c, 0x3a, 0x52, 0xa9, 0x47, 0xbc, + 0x6a, 0x6d, 0x07, 0xc5, 0x35, 0xca, 0xed, 0x72, 0x1e, 0xa3, 0x91, 0xe9, + 0x7a, 0x0f, 0x8a, 0x6c, 0x96, 0xd1, 0xfc, 0xe9, 0x77, 0x8f, 0x19, 0x20, + 0xce, 0x9a, 0x4b, 0x87, 0x4a, 0x15, 0xe3, 0x77, 0xaf, 0x6f, 0x2e, 0x9d, + 0x8c, 0x50, 0xae, 0x1d, 0x29, 0x92, 0x5c, 0x2e, 0xe9, 0x69, 0x2e, 0x39, + 0x2c, 0x69, 0xcd, 0x24, 0x06, 0xfd, 0x2d, 0x2d, 0xc5, 0x5f, 0x1a, 0x61, + 0x1b, 0x0f, 0x60, 0x37, 0xe9, 0x4e, 0xf2, 0xff, 0x00, 0x5e, 0x37, 0x64, + 0x97, 0x1a, 0xd6, 0x94, 0xf6, 0x4c, 0x87, 0x9f, 0x5d, 0x2a, 0xd5, 0x50, + 0x64, 0xb7, 0x1a, 0x65, 0xac, 0xd0, 0x57, 0x97, 0x4a, 0x4a, 0xc5, 0x5b, + 0x25, 0xb8, 0xd3, 0xdd, 0x72, 0x0b, 0x3e, 0x95, 0x92, 0xb5, 0x57, 0x74, + 0x5b, 0x74, 0xc8, 0xac, 0xa9, 0xa5, 0xb8, 0x65, 0x52, 0x70, 0xe9, 0x56, + 0xe2, 0x94, 0x7d, 0x09, 0xa4, 0x78, 0x3b, 0x53, 0xd5, 0x71, 0x90, 0x43, + 0x3e, 0x96, 0x86, 0xef, 0x2c, 0x3f, 0xb4, 0x9e, 0x9c, 0xe1, 0xb4, 0x3c, + 0x67, 0x0e, 0x8e, 0x97, 0x6f, 0xd4, 0x90, 0x6c, 0x96, 0xd3, 0xfd, 0xa7, + 0xaa, 0xf8, 0x0a, 0x7d, 0xab, 0xe9, 0x2f, 0xb2, 0x24, 0x54, 0xb4, 0x6d, + 0x07, 0xc5, 0x32, 0x4b, 0x85, 0x04, 0x96, 0x3d, 0x19, 0x16, 0x49, 0x60, + 0x3b, 0xc3, 0x3b, 0x69, 0xea, 0xb8, 0x48, 0x23, 0x97, 0x4b, 0xd0, 0x7c, + 0x53, 0x12, 0x35, 0x8e, 0x94, 0x5a, 0x2b, 0x37, 0xd0, 0x7c, 0x53, 0x6a, + 0x3e, 0x3a, 0x5b, 0x41, 0xf0, 0x93, 0xfe, 0x52, 0xd5, 0x61, 0x90, 0xf3, + 0xeb, 0xf1, 0x57, 0x52, 0xcf, 0xf5, 0x2b, 0x7a, 0x36, 0x83, 0x4c, 0x49, + 0x19, 0x0c, 0xbd, 0xce, 0xe6, 0x49, 0x47, 0xf1, 0x6f, 0xd1, 0xfd, 0xb4, + 0xc5, 0xdf, 0x1b, 0x29, 0xea, 0xb5, 0xdc, 0xab, 0x34, 0xee, 0x97, 0xa0, + 0xf8, 0xa6, 0x49, 0x70, 0xe9, 0x69, 0x2e, 0x34, 0xf4, 0x2f, 0x1d, 0xfe, + 0x63, 0x46, 0xcf, 0xe7, 0xba, 0xb0, 0xe8, 0x9a, 0x2c, 0xff, 0x00, 0x0a, + 0x05, 0xed, 0x07, 0xf7, 0x4c, 0x29, 0xcb, 0x8d, 0x1d, 0xbf, 0x52, 0xcb, + 0x8e, 0xb6, 0xe6, 0x65, 0xc7, 0xe9, 0xbd, 0x33, 0x88, 0xdc, 0x5d, 0x89, + 0xdf, 0xf7, 0x3d, 0xd6, 0xf3, 0x1d, 0x11, 0x79, 0x86, 0x54, 0x0e, 0x23, + 0x60, 0x2e, 0xee, 0xda, 0x99, 0xb9, 0xdb, 0x48, 0x78, 0x3e, 0x9a, 0xb4, + 0xe5, 0xe3, 0x38, 0xf4, 0x54, 0x97, 0x7f, 0xc5, 0xbf, 0xe1, 0xbc, 0xee, + 0x00, 0x68, 0xff, 0x00, 0x74, 0xcd, 0xe6, 0x50, 0x3f, 0x03, 0x03, 0xa1, + 0x8f, 0x48, 0x4b, 0x0f, 0xd7, 0xc6, 0xf0, 0x18, 0x08, 0x0d, 0x07, 0x02, + 0xf9, 0x00, 0x9a, 0xe2, 0xe8, 0xda, 0xf8, 0xf4, 0x93, 0x72, 0x41, 0xc4, + 0xec, 0x5d, 0x0d, 0x5d, 0xc1, 0x7c, 0x55, 0x8b, 0x43, 0x11, 0xab, 0xf9, + 0xaa, 0xeb, 0xf5, 0xbf, 0xac, 0xf8, 0x69, 0x63, 0x41, 0xd0, 0xd6, 0x2d, + 0x04, 0x4e, 0xae, 0xe0, 0xb9, 0x1e, 0x5c, 0x22, 0x58, 0xfa, 0xb5, 0xae, + 0xfe, 0x59, 0x6f, 0x40, 0x3e, 0xb5, 0xa9, 0xa3, 0x39, 0x7e, 0x62, 0x8a, + 0xf1, 0x54, 0x78, 0x0f, 0x41, 0x54, 0x0c, 0x44, 0xf5, 0x86, 0x5c, 0x2b, + 0xdc, 0x11, 0xc4, 0x40, 0xeb, 0xc8, 0x25, 0x6f, 0x21, 0x8e, 0x3d, 0xa9, + 0xda, 0xe0, 0x10, 0x7d, 0xa6, 0x03, 0x57, 0x34, 0xe7, 0xc2, 0x8a, 0x5a, + 0xe0, 0xc6, 0x47, 0x47, 0x76, 0x3c, 0x82, 0x58, 0x36, 0x94, 0x3d, 0x5f, + 0xc9, 0x49, 0x71, 0x6a, 0x00, 0xf2, 0x7b, 0x70, 0xcc, 0x20, 0xa8, 0xe9, + 0x23, 0xa3, 0x02, 0x08, 0x04, 0x48, 0x80, 0x46, 0x06, 0x3c, 0x7f, 0xed, + 0xe9, 0x0a, 0x0a, 0xce, 0x41, 0x1f, 0xc2, 0x40, 0x04, 0x99, 0x00, 0x49, + 0xc0, 0x7c, 0x63, 0x18, 0xac, 0x93, 0x80, 0xa8, 0x64, 0x1c, 0x32, 0xe2, + 0x3f, 0x32, 0x9c, 0x91, 0xa8, 0xed, 0x2b, 0xa1, 0xcb, 0x2e, 0xdc, 0x2c, + 0x28, 0xbb, 0x42, 0x73, 0xe0, 0x9f, 0x79, 0x77, 0xe2, 0xbb, 0x6a, 0x18, + 0x60, 0x3b, 0x40, 0xe5, 0xc8, 0x24, 0xbf, 0xbc, 0x44, 0x97, 0x7e, 0x03, + 0xd8, 0xd4, 0x20, 0x30, 0x1b, 0x97, 0x9c, 0xf8, 0xce, 0x67, 0xce, 0x26, + 0x42, 0x07, 0xb6, 0xa0, 0x9e, 0x4e, 0x7c, 0x83, 0xf8, 0x09, 0xc0, 0xce, + 0x67, 0x21, 0xab, 0xb8, 0xee, 0xe7, 0xca, 0x27, 0xae, 0xc7, 0x42, 0x79, + 0x74, 0xb1, 0xa6, 0x17, 0xc5, 0x89, 0xa2, 0xf4, 0x02, 0x50, 0x31, 0xaf, + 0x58, 0x65, 0xc8, 0x39, 0x4d, 0x62, 0x18, 0x86, 0xe1, 0xc7, 0x3e, 0x5c, + 0x27, 0xc3, 0x6e, 0x02, 0x5d, 0xff, 0x00, 0x1e, 0xe6, 0xb3, 0x00, 0x2f, + 0x3b, 0x08, 0xf2, 0x31, 0xd1, 0x84, 0x39, 0x25, 0xdd, 0xee, 0xbe, 0x1c, + 0xad, 0xe9, 0xdc, 0x14, 0xb4, 0xfd, 0x86, 0xa5, 0xe6, 0x9f, 0x60, 0xe0, + 0x33, 0xe4, 0x65, 0x26, 0x08, 0xcb, 0x1c, 0x45, 0x84, 0x4f, 0x9f, 0x7a, + 0xd6, 0x12, 0x16, 0x9a, 0x86, 0xf7, 0x31, 0x2f, 0x24, 0x99, 0x98, 0x9e, + 0x49, 0xd9, 0x1c, 0xa4, 0xb8, 0x80, 0x7c, 0x8e, 0x2d, 0xfc, 0x93, 0xf0, + 0x19, 0x44, 0x71, 0x6c, 0x3c, 0x9e, 0x4c, 0x12, 0x08, 0x22, 0x04, 0x17, + 0x83, 0x61, 0x0d, 0x7b, 0x82, 0x22, 0xc2, 0x20, 0x75, 0xa7, 0xf6, 0xb5, + 0x97, 0x2c, 0x33, 0x95, 0x08, 0x5e, 0x64, 0x07, 0x7d, 0x22, 0xc4, 0x92, + 0x49, 0x31, 0x24, 0xbc, 0x9b, 0x49, 0xe5, 0x1d, 0x91, 0xca, 0x21, 0x88, + 0x11, 0xee, 0x3c, 0x50, 0xc3, 0xf9, 0xcc, 0xbe, 0x00, 0x94, 0x46, 0xf2, + 0x6a, 0xc8, 0x79, 0xbb, 0x95, 0x04, 0x82, 0x08, 0x81, 0x04, 0x10, 0x6f, + 0x12, 0x61, 0xdb, 0x02, 0x56, 0x1a, 0xc6, 0x51, 0xe6, 0xc2, 0x62, 0xa1, + 0x01, 0x69, 0xa8, 0x67, 0xa0, 0x79, 0x62, 0x49, 0x24, 0x92, 0xf2, 0x62, + 0x49, 0xe5, 0x9d, 0x91, 0x98, 0x44, 0x30, 0x55, 0x98, 0xf0, 0x05, 0x7c, + 0xbe, 0xab, 0x2a, 0x10, 0x8c, 0xa6, 0xbc, 0x87, 0xa1, 0x0c, 0x49, 0xe5, + 0xc1, 0x71, 0x78, 0x98, 0x88, 0x60, 0x8e, 0xb1, 0x9d, 0xc4, 0x40, 0x87, + 0x55, 0x74, 0xa1, 0x17, 0x47, 0x99, 0xb7, 0xc7, 0x39, 0xea, 0xca, 0x5f, + 0xdb, 0x98, 0x97, 0x92, 0x4c, 0xcc, 0x4f, 0x31, 0x15, 0x6c, 0xc8, 0x0c, + 0x9f, 0x1f, 0x4b, 0x38, 0x49, 0x28, 0xf1, 0xe1, 0x09, 0x56, 0xb4, 0x99, + 0xf6, 0x96, 0x2f, 0xe6, 0x9d, 0xa4, 0xb9, 0xe2, 0x07, 0x11, 0x75, 0xf3, + 0xcd, 0xce, 0x84, 0x79, 0x67, 0xe9, 0xae, 0x58, 0x8e, 0xd3, 0x38, 0x73, + 0x70, 0xb7, 0xd4, 0x1f, 0x47, 0x22, 0x7b, 0x13, 0xcb, 0xbe, 0x5d, 0x60, + 0xbe, 0x31, 0x39, 0x99, 0x5c, 0x07, 0x39, 0x0b, 0x35, 0x00, 0xde, 0x2a, + 0x39, 0xc8, 0xde, 0x09, 0xe5, 0x61, 0x62, 0xc4, 0x5a, 0x05, 0x66, 0x16, + 0x4a, 0x73, 0x20, 0xf3, 0xae, 0xd3, 0x17, 0xa0, 0xe5, 0x87, 0x69, 0xc2, + 0x30, 0x60, 0x41, 0x88, 0x30, 0xde, 0x3e, 0x3c, 0xf2, 0x72, 0x9b, 0x1c, + 0xa5, 0x29, 0x05, 0x81, 0x2f, 0x64, 0xe3, 0xcf, 0x56, 0x98, 0xca, 0x77, + 0x61, 0x60, 0xe4, 0xde, 0x3c, 0x90, 0xac, 0x3c, 0x3d, 0xf6, 0xb7, 0xa0, + 0x11, 0xc0, 0xfd, 0xa5, 0x4e, 0xe6, 0x36, 0x44, 0x87, 0x5b, 0x53, 0x48, + 0xc2, 0x6c, 0x91, 0xec, 0x62, 0xce, 0x99, 0xef, 0xc5, 0x45, 0xa4, 0xa3, + 0xec, 0x05, 0xe7, 0xb0, 0xd0, 0x9e, 0xec, 0x04, 0x81, 0xe4, 0x09, 0xac, + 0x3d, 0x60, 0x1f, 0x8f, 0x43, 0x00, 0x91, 0x0c, 0x09, 0x17, 0x55, 0x74, + 0x1b, 0xef, 0x37, 0x6f, 0xb8, 0xdd, 0xbe, 0xf3, 0x76, 0xfb, 0xcd, 0xdb, + 0xee, 0x37, 0x6f, 0xbc, 0xdd, 0xbe, 0xf3, 0x76, 0xfb, 0xcd, 0xdb, 0x2e, + 0x94, 0x50, 0xd5, 0xbe, 0xf3, 0x76, 0xfb, 0xcd, 0xdb, 0xef, 0x37, 0x62, + 0x49, 0x93, 0x12, 0x4f, 0x9f, 0xf0, 0xbf, 0xff, 0xc4, 0x00, 0x2b, 0x11, + 0x00, 0x01, 0x01, 0x04, 0x0a, 0x02, 0x03, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x00, 0x21, 0x31, 0xf0, 0x20, 0x41, + 0x50, 0x51, 0x61, 0x71, 0x81, 0x91, 0xa1, 0xc1, 0x40, 0xb1, 0x10, 0x30, + 0xd1, 0xe1, 0xf1, 0x60, 0xff, 0xda, 0x00, 0x08, 0x01, 0x02, 0x01, 0x01, + 0x3f, 0x10, 0xff, 0x00, 0x80, 0x43, 0x73, 0x28, 0x11, 0x20, 0x6a, 0xd8, + 0x83, 0x70, 0xc4, 0x71, 0x16, 0x60, 0x3b, 0x69, 0x13, 0xb6, 0x91, 0xbb, + 0x69, 0x9b, 0xb6, 0x9c, 0xbb, 0x69, 0x6b, 0xb6, 0x96, 0xbb, 0x69, 0x6b, + 0xb6, 0x96, 0xbb, 0x69, 0xcb, 0xb6, 0xf5, 0x98, 0xd7, 0x45, 0xa7, 0x2e, + 0xda, 0x44, 0xed, 0xa4, 0x4e, 0xdb, 0xfc, 0x77, 0xeb, 0x7f, 0x98, 0xfd, + 0x65, 0x17, 0x8d, 0xc3, 0x28, 0xbc, 0x6f, 0xe2, 0x8a, 0x51, 0x5c, 0xac, + 0x9c, 0x80, 0x52, 0x76, 0x41, 0x5a, 0x06, 0x00, 0xbf, 0x0b, 0xcb, 0xd0, + 0x0f, 0x60, 0xc4, 0xf0, 0x1a, 0x44, 0x9d, 0x54, 0xa7, 0x01, 0xb0, 0xe2, + 0x7a, 0xc9, 0x34, 0x6c, 0x76, 0xdf, 0x86, 0xff, 0x00, 0x6f, 0x39, 0xd1, + 0x89, 0x62, 0x75, 0x26, 0x22, 0x89, 0x25, 0x22, 0xf7, 0xb4, 0x8d, 0xdb, + 0x12, 0x44, 0x97, 0x32, 0xbe, 0xcd, 0xf0, 0xc5, 0xec, 0xfb, 0xcd, 0xd1, + 0xbd, 0xf0, 0x94, 0xd6, 0x83, 0xba, 0x84, 0xbb, 0x86, 0x41, 0x14, 0x7d, + 0xf5, 0xef, 0x1f, 0xa6, 0x43, 0x20, 0x7b, 0xb3, 0xfe, 0xff, 0x00, 0x7b, + 0x6a, 0xd3, 0xa9, 0xd9, 0xa6, 0x13, 0x7c, 0x3e, 0x56, 0xb9, 0x73, 0x29, + 0x8a, 0x95, 0xbd, 0x4b, 0x3b, 0x44, 0xc5, 0x41, 0x40, 0x5f, 0x05, 0x19, + 0xee, 0xc2, 0xaa, 0x2a, 0xe3, 0x6f, 0x83, 0x69, 0x50, 0x52, 0x29, 0xba, + 0xb0, 0x0f, 0x72, 0x1f, 0x60, 0xf0, 0x8d, 0x8e, 0xd9, 0x8c, 0x3c, 0xf5, + 0xbd, 0xd3, 0x00, 0x44, 0x96, 0x7f, 0x82, 0x1b, 0x2a, 0xbc, 0xd7, 0x96, + 0x15, 0xec, 0x68, 0x0c, 0x4a, 0x2a, 0x9d, 0x89, 0xd5, 0xa5, 0x64, 0x28, + 0xc7, 0xea, 0x43, 0x10, 0xc2, 0xe0, 0x0f, 0x79, 0xc6, 0xe1, 0x0a, 0xcd, + 0x40, 0x90, 0x24, 0x24, 0x98, 0x92, 0x54, 0xb4, 0xcd, 0x7f, 0x09, 0x3c, + 0x44, 0xfb, 0x64, 0xd3, 0x6d, 0x77, 0xad, 0xa0, 0x5c, 0x03, 0xe3, 0x29, + 0xed, 0x1a, 0xfe, 0xdf, 0x39, 0x37, 0x52, 0xfa, 0x09, 0xed, 0x67, 0x2f, + 0x0b, 0xfb, 0xf0, 0x80, 0x61, 0x08, 0x4d, 0x4d, 0xa3, 0x4c, 0xa3, 0x5f, + 0x19, 0x4f, 0xc9, 0x5f, 0x89, 0xbb, 0xfb, 0x35, 0x36, 0xba, 0x4c, 0xe1, + 0xf0, 0xf0, 0x5c, 0x48, 0x21, 0xe0, 0x82, 0x84, 0x1a, 0x88, 0x32, 0xb9, + 0x36, 0x1b, 0x87, 0x14, 0x44, 0x88, 0xa8, 0x85, 0xe2, 0x80, 0x02, 0x1e, + 0x91, 0x3f, 0x40, 0x4a, 0xd4, 0x5c, 0xcc, 0x00, 0xd4, 0x90, 0x18, 0x86, + 0x22, 0x92, 0x52, 0x66, 0xab, 0x85, 0x41, 0xc1, 0x8e, 0xc3, 0xd4, 0x2f, + 0xaa, 0x39, 0x0d, 0xdb, 0x8f, 0x06, 0xf9, 0x9d, 0x71, 0xa9, 0x3e, 0xc9, + 0xbf, 0xf2, 0x8c, 0xe1, 0xc7, 0x5f, 0x13, 0x28, 0xd3, 0x33, 0x7b, 0x66, + 0xb5, 0xa3, 0xe1, 0x08, 0x0d, 0x1f, 0x9a, 0xc6, 0x20, 0x92, 0x04, 0x14, + 0x24, 0xa0, 0x8a, 0x88, 0xe3, 0xa6, 0x08, 0x5a, 0xc3, 0xc5, 0xc4, 0x38, + 0x8d, 0x0a, 0xe7, 0x1a, 0x68, 0x5f, 0x82, 0x74, 0x0e, 0xc3, 0xe6, 0x67, + 0x9f, 0x2a, 0x67, 0x9f, 0xb6, 0xbd, 0x05, 0xf3, 0x35, 0x84, 0x65, 0x2e, + 0xc0, 0x17, 0xb8, 0x87, 0x40, 0x8d, 0x4b, 0xab, 0xa6, 0x4e, 0x6e, 0x5e, + 0xe4, 0x8b, 0x25, 0x38, 0xb7, 0x6c, 0x4e, 0xef, 0x03, 0xb1, 0x4e, 0xe9, + 0xf0, 0x8c, 0x69, 0x44, 0xe6, 0x93, 0xea, 0x56, 0xc5, 0xe5, 0xff, 0x00, + 0xd2, 0x57, 0x4a, 0x6a, 0xc2, 0x46, 0xf2, 0x2e, 0x9e, 0x34, 0x3e, 0x07, + 0xee, 0x15, 0xce, 0x71, 0xf0, 0xf9, 0x49, 0x26, 0x14, 0xf8, 0x4b, 0x2d, + 0xe7, 0x24, 0x9f, 0x74, 0xf8, 0x4b, 0x2d, 0xe5, 0x24, 0xde, 0x9f, 0x09, + 0x24, 0xf1, 0xf7, 0xca, 0xdf, 0x19, 0xb9, 0xee, 0xf3, 0x39, 0x4a, 0x6f, + 0x09, 0x4d, 0x99, 0xce, 0x53, 0xc2, 0x9a, 0xb0, 0x9d, 0xf0, 0xf0, 0xb9, + 0x4a, 0x6f, 0x09, 0x49, 0x49, 0xdf, 0xf4, 0xd8, 0xbc, 0xbc, 0x9b, 0xd3, + 0xe1, 0x19, 0xfe, 0x4c, 0xe1, 0xf1, 0xea, 0xa9, 0xae, 0xcf, 0x33, 0x84, + 0x66, 0x66, 0x6b, 0xb2, 0xb9, 0x49, 0x27, 0xd5, 0x3e, 0x12, 0xcb, 0x79, + 0x49, 0x27, 0xf6, 0x97, 0x09, 0x65, 0xba, 0x35, 0xf4, 0x77, 0x4f, 0x84, + 0x62, 0x67, 0x3f, 0x99, 0xde, 0xc7, 0xe5, 0x3f, 0xd2, 0x57, 0x4a, 0x7c, + 0x25, 0x96, 0xf2, 0x94, 0xce, 0x13, 0xfc, 0x25, 0x74, 0xb2, 0xf9, 0x4a, + 0x6f, 0x09, 0x65, 0xbc, 0xa4, 0x93, 0xee, 0x9f, 0x09, 0x65, 0xb1, 0x58, + 0xb9, 0xfc, 0x29, 0xf0, 0x96, 0x5b, 0xca, 0x53, 0x38, 0x4b, 0x2d, 0xe5, + 0xe4, 0x9f, 0x54, 0xf8, 0x49, 0x27, 0xdd, 0x29, 0xbe, 0xb7, 0xcd, 0x56, + 0x2f, 0x2f, 0x9c, 0x91, 0xd2, 0x9f, 0x09, 0x65, 0xbc, 0xa3, 0xe4, 0x8f, + 0x54, 0xf8, 0x47, 0xc9, 0x0e, 0xec, 0xa9, 0xda, 0x7f, 0x2b, 0x6e, 0x51, + 0xf2, 0x47, 0xaa, 0x7c, 0x25, 0x96, 0xf2, 0x8f, 0x92, 0x3d, 0x53, 0xe1, + 0x2c, 0xb4, 0x1f, 0xe4, 0x93, 0x2a, 0x7c, 0x25, 0x8c, 0xcc, 0xf1, 0x47, + 0x94, 0xa6, 0x70, 0x96, 0x3b, 0xc7, 0xfb, 0xdd, 0x0e, 0x52, 0x4d, 0xa9, + 0xf0, 0x96, 0x33, 0x38, 0xee, 0xcb, 0xbc, 0xae, 0x7a, 0x57, 0x73, 0x5f, + 0x35, 0x09, 0x7f, 0xcf, 0x29, 0x4c, 0xe1, 0x2c, 0xb7, 0x94, 0xa6, 0x70, + 0x96, 0x33, 0x2f, 0xf9, 0x7c, 0xcf, 0x1c, 0xfc, 0x72, 0x99, 0xc9, 0x1d, + 0x29, 0xf0, 0x96, 0x4b, 0xdc, 0xbe, 0x70, 0xf8, 0xe5, 0x29, 0x9c, 0x25, + 0x90, 0xcc, 0xce, 0x4d, 0x21, 0xfe, 0xe4, 0xfc, 0x72, 0x94, 0xde, 0x12, + 0xc7, 0x66, 0x76, 0xe3, 0xe2, 0x09, 0x33, 0x5f, 0xc7, 0x29, 0x4d, 0xe1, + 0x2c, 0xb7, 0x94, 0xa6, 0xf0, 0x96, 0x33, 0x33, 0x22, 0x87, 0x18, 0x66, + 0xdc, 0xa5, 0x37, 0x84, 0xb1, 0xd9, 0xfd, 0xf8, 0x86, 0x0d, 0x58, 0x71, + 0x84, 0x7f, 0x91, 0xe1, 0xdb, 0xb7, 0x29, 0x4d, 0x07, 0xf7, 0x88, 0xdb, + 0x52, 0xbb, 0xaa, 0x8d, 0x97, 0xcb, 0xd3, 0x01, 0xe6, 0x21, 0xb1, 0xfe, + 0xcd, 0x76, 0x54, 0x5e, 0x0f, 0x63, 0xf2, 0x98, 0x3c, 0xb0, 0x0a, 0xff, + 0x00, 0x8a, 0xf3, 0xb2, 0xe2, 0xc2, 0x39, 0x9f, 0x64, 0xe2, 0x98, 0x3c, + 0xb8, 0x86, 0xe0, 0x1e, 0xac, 0xb0, 0x71, 0x5e, 0x43, 0x60, 0x4c, 0xbf, + 0x69, 0xa8, 0xab, 0xc6, 0xeb, 0xda, 0xca, 0xbe, 0x74, 0xed, 0xf7, 0xb0, + 0x22, 0xaf, 0x19, 0xc2, 0x98, 0x90, 0x45, 0x2a, 0x20, 0x5e, 0x5c, 0x6a, + 0xa1, 0xd8, 0xd9, 0x33, 0x33, 0x97, 0xc2, 0xd9, 0x14, 0x12, 0x2e, 0x2f, + 0x06, 0x84, 0xfd, 0x18, 0x94, 0x01, 0x92, 0xba, 0xa1, 0x56, 0x02, 0xc9, + 0xc0, 0xe0, 0x72, 0x50, 0xbc, 0x2f, 0xd2, 0x9a, 0x88, 0x4f, 0x4a, 0xdc, + 0x21, 0x70, 0x1c, 0xac, 0x89, 0x9e, 0x19, 0x72, 0x60, 0xeb, 0x37, 0x07, + 0x18, 0x3e, 0x95, 0xb3, 0x59, 0x27, 0x20, 0x13, 0x90, 0x9d, 0x2c, 0x95, + 0x65, 0x6f, 0xf2, 0x3e, 0x88, 0x07, 0x32, 0x7e, 0x92, 0x01, 0x04, 0x17, + 0x82, 0x10, 0x8b, 0xc1, 0x63, 0xbc, 0xdc, 0x5c, 0xb7, 0x9e, 0x5a, 0x82, + 0x30, 0xba, 0xc7, 0xbb, 0x12, 0x5e, 0x95, 0x00, 0xfd, 0x80, 0x16, 0x01, + 0x02, 0x08, 0x07, 0x0f, 0xaa, 0x11, 0x22, 0x92, 0xf6, 0x17, 0x21, 0x75, + 0x8f, 0x13, 0x1f, 0x93, 0x89, 0x39, 0x2a, 0x0c, 0xd7, 0xeb, 0x09, 0x58, + 0x02, 0x2d, 0xc6, 0x20, 0xe8, 0x40, 0x2c, 0x04, 0x88, 0x2e, 0x24, 0x41, + 0x18, 0x85, 0x04, 0x3f, 0x19, 0x4b, 0x14, 0x02, 0x40, 0x00, 0xa4, 0x80, + 0x03, 0x12, 0x50, 0x30, 0x42, 0xc0, 0x00, 0xcc, 0xd6, 0x75, 0x2a, 0x75, + 0xfb, 0x10, 0x04, 0x39, 0x79, 0xc1, 0x1c, 0x94, 0x21, 0x17, 0xbe, 0xe3, + 0x62, 0xa8, 0x1c, 0x05, 0xd7, 0x29, 0x53, 0x60, 0xa7, 0x02, 0x85, 0xd5, + 0xfd, 0x89, 0xe4, 0x1b, 0x00, 0x50, 0x6a, 0x09, 0xd5, 0x62, 0xa0, 0x91, + 0x0b, 0x31, 0x4d, 0x5a, 0x04, 0x1a, 0x7d, 0xca, 0x24, 0x08, 0xa1, 0x99, + 0x52, 0x1b, 0xbf, 0x51, 0x61, 0xa2, 0xaf, 0xb4, 0x22, 0x0a, 0xa2, 0x62, + 0x8a, 0xe0, 0x6e, 0xfb, 0xd4, 0x48, 0x8a, 0x8c, 0x44, 0x03, 0x50, 0xfc, + 0xc0, 0xb0, 0xd0, 0xc9, 0xbd, 0x60, 0x2a, 0x6c, 0xfc, 0xc9, 0xf0, 0x1d, + 0x63, 0xdb, 0x8f, 0xc2, 0x0e, 0x85, 0xae, 0xc1, 0x59, 0x21, 0x1c, 0x82, + 0xad, 0x5c, 0x35, 0xf0, 0x50, 0x04, 0x3e, 0x3c, 0xd1, 0xd8, 0xa1, 0xc0, + 0x2d, 0x82, 0xf0, 0x60, 0x0b, 0x82, 0x1a, 0x92, 0xa6, 0xe4, 0x47, 0xf8, + 0x24, 0x02, 0x08, 0x2f, 0x04, 0x10, 0x46, 0x06, 0x2c, 0x64, 0x92, 0x80, + 0xbc, 0xaa, 0xa4, 0xf2, 0xd9, 0xc6, 0xb5, 0xdf, 0xcf, 0x35, 0x52, 0x5e, + 0x57, 0x04, 0x4f, 0x43, 0x12, 0x18, 0x00, 0x00, 0x01, 0xc0, 0x04, 0x02, + 0xe0, 0x3c, 0x24, 0xc0, 0x8b, 0xaf, 0x23, 0xc6, 0x2e, 0xbc, 0x5d, 0x72, + 0x92, 0xef, 0x3d, 0x74, 0x85, 0x48, 0xc0, 0x3f, 0x42, 0xf2, 0xe0, 0x08, + 0xf0, 0xc8, 0x00, 0x41, 0x78, 0x20, 0x82, 0x30, 0x21, 0x0b, 0x1e, 0xf1, + 0x38, 0xbd, 0xe0, 0xbc, 0x18, 0x05, 0x71, 0x10, 0x31, 0x51, 0xe6, 0x94, + 0x0c, 0x49, 0x7e, 0x00, 0xf2, 0x76, 0x05, 0x31, 0x60, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x0c, 0x07, 0x88, 0xb8, 0x08, 0x0a, 0xe9, 0x62, 0x21, 0x0e, + 0x87, 0xdb, 0xca, 0x07, 0x79, 0x89, 0x91, 0xc7, 0x40, 0x11, 0x3a, 0x97, + 0x69, 0x8f, 0x8a, 0x02, 0x01, 0x40, 0x10, 0x45, 0xe0, 0xb8, 0xb1, 0x0a, + 0xbd, 0x51, 0xbc, 0x17, 0x95, 0xcf, 0x11, 0xc6, 0xe8, 0x79, 0x67, 0x1b, + 0x59, 0x79, 0xb8, 0x07, 0x93, 0xb4, 0x31, 0x4b, 0xd8, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x03, 0x01, 0xe3, 0x2e, 0x03, 0x17, 0x60, 0x79, 0x18, 0xc2, + 0xb3, 0xcb, 0xc3, 0x95, 0x55, 0x3c, 0xb5, 0x42, 0x0f, 0x74, 0x5e, 0x02, + 0xbd, 0x41, 0x72, 0x04, 0x23, 0xe3, 0x90, 0x08, 0x20, 0x85, 0x04, 0x10, + 0x45, 0xe0, 0xb8, 0x86, 0xba, 0x81, 0x15, 0xe5, 0x16, 0xce, 0x26, 0x0a, + 0x0e, 0x5e, 0x4d, 0xc4, 0x9d, 0x81, 0x13, 0xb3, 0x86, 0x25, 0x80, 0x00, + 0x00, 0x1c, 0x00, 0x40, 0x2e, 0x03, 0xc8, 0x47, 0x11, 0x13, 0x53, 0x2f, + 0x1a, 0x17, 0xee, 0xcf, 0xe7, 0x84, 0xcd, 0xf2, 0xe7, 0x79, 0x0f, 0x7e, + 0x0e, 0x01, 0x0d, 0xe3, 0xb7, 0x93, 0x18, 0xb1, 0xcd, 0x58, 0xf3, 0xbc, + 0xa0, 0x16, 0xf7, 0x81, 0xbd, 0x01, 0xad, 0x84, 0xcd, 0xdb, 0xa3, 0xc2, + 0xf8, 0xc7, 0x1a, 0x2f, 0x10, 0x72, 0x06, 0x38, 0xaa, 0x07, 0x38, 0x95, + 0x60, 0x10, 0x20, 0x80, 0x70, 0xf2, 0x95, 0x12, 0xb7, 0x10, 0x76, 0x01, + 0xb8, 0x0c, 0xf9, 0xcd, 0xc6, 0xa8, 0x4a, 0x9f, 0x19, 0x18, 0x91, 0x0e, + 0xb1, 0x01, 0x85, 0x48, 0x08, 0x8b, 0xc9, 0xf3, 0x17, 0x08, 0xaf, 0xb8, + 0x17, 0x34, 0x27, 0x62, 0x33, 0x33, 0x73, 0xd7, 0x20, 0xf2, 0x65, 0xfe, + 0x23, 0xd0, 0xd4, 0x94, 0x63, 0x15, 0x2b, 0x52, 0xa6, 0xe2, 0x01, 0x0e, + 0xf3, 0x57, 0xaa, 0x1e, 0x57, 0x07, 0xeb, 0xc1, 0xb9, 0x56, 0xa6, 0x20, + 0x82, 0x85, 0x41, 0x11, 0x07, 0x90, 0x45, 0x44, 0x1c, 0x30, 0xbd, 0x84, + 0xcc, 0xe9, 0xe1, 0x22, 0xb8, 0x05, 0x25, 0xc9, 0x15, 0x5a, 0x92, 0xb5, + 0x61, 0x8a, 0xb1, 0xe5, 0x15, 0x2e, 0x80, 0x40, 0x32, 0x5a, 0xfc, 0xe5, + 0x94, 0x67, 0x0b, 0xd0, 0x4a, 0xb5, 0x65, 0xab, 0x18, 0x69, 0x5e, 0x46, + 0x37, 0x2d, 0xd5, 0xa1, 0x14, 0x61, 0xfd, 0xfb, 0x0c, 0x1d, 0xa5, 0xd3, + 0xd2, 0xad, 0x95, 0x94, 0x81, 0xb0, 0x20, 0xa5, 0x70, 0x7a, 0xb4, 0xad, + 0x90, 0x4c, 0x03, 0xcb, 0x46, 0xa4, 0x52, 0x84, 0x3c, 0x6e, 0x14, 0x64, + 0xa8, 0x70, 0x55, 0x62, 0x95, 0xcf, 0xf6, 0xef, 0x95, 0x17, 0xcc, 0x91, + 0xbb, 0x2c, 0xde, 0x2f, 0xcb, 0xe3, 0x6b, 0xf7, 0x92, 0xf6, 0xd6, 0x64, + 0x1e, 0x59, 0x45, 0xe3, 0xe2, 0x7f, 0x37, 0x65, 0x17, 0xb3, 0xbf, 0x3f, + 0x98, 0xb2, 0x8f, 0x7d, 0xfe, 0x16, 0xaa, 0x92, 0xc4, 0x82, 0x31, 0x3c, + 0xa0, 0xd9, 0x5f, 0x51, 0x2e, 0x62, 0xa0, 0x89, 0x40, 0x23, 0x87, 0x57, + 0xde, 0x04, 0xa6, 0x50, 0x4b, 0x08, 0x92, 0x24, 0xcc, 0x03, 0xec, 0x60, + 0x36, 0x69, 0x33, 0xa6, 0x91, 0x3a, 0x69, 0x13, 0xa6, 0x93, 0x3a, 0x69, + 0x33, 0xa6, 0x93, 0x3a, 0x69, 0x13, 0xa6, 0x91, 0x3a, 0x69, 0x13, 0xa6, + 0x91, 0x3a, 0x69, 0x33, 0xa6, 0x91, 0x3a, 0x60, 0x38, 0x03, 0x20, 0x1e, + 0x87, 0xfc, 0x2f, 0xff, 0xc4, 0x00, 0x2b, 0x10, 0x01, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x01, 0x04, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x11, 0x21, 0x31, 0x41, 0x00, 0x51, 0x61, 0x71, 0x81, 0x91, 0xa1, + 0xb1, 0xc1, 0xd1, 0xf0, 0x20, 0x40, 0xe1, 0xf1, 0x30, 0x10, 0x60, 0x50, + 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x01, 0x3f, 0x10, 0xff, 0x00, + 0xf8, 0x00, 0x5a, 0x05, 0x7a, 0x05, 0xfd, 0x38, 0x3e, 0x17, 0xd2, 0xfe, + 0xdc, 0x1d, 0x48, 0x32, 0x88, 0x7b, 0x50, 0xe4, 0xd5, 0x2e, 0x6b, 0x3d, + 0xd0, 0xe2, 0xe8, 0xf1, 0x32, 0x22, 0x46, 0x64, 0x1c, 0x6f, 0x93, 0xf4, + 0xc4, 0xb5, 0x67, 0x6c, 0x30, 0x7b, 0xe2, 0x70, 0xe7, 0x49, 0xd6, 0x70, + 0xe2, 0x1f, 0xae, 0x48, 0xd5, 0x66, 0x87, 0x77, 0x06, 0xaf, 0x82, 0x49, + 0x66, 0x50, 0x48, 0xcd, 0x8e, 0x38, 0xc4, 0x23, 0x29, 0x0f, 0x49, 0x92, + 0x02, 0xcd, 0x9c, 0x4b, 0x23, 0x19, 0x9f, 0x47, 0xe4, 0x87, 0x29, 0x97, + 0x89, 0xd2, 0xcc, 0x4d, 0xb5, 0x35, 0x3d, 0xf3, 0x74, 0x36, 0x5e, 0x1d, + 0xd9, 0xc8, 0x5b, 0xac, 0x58, 0xfa, 0x92, 0x7e, 0x39, 0x06, 0x94, 0xe1, + 0x95, 0x9c, 0x44, 0x93, 0xf1, 0xc8, 0x2b, 0x7c, 0x5a, 0xfa, 0x93, 0x9f, + 0xd6, 0xf7, 0xed, 0xe2, 0x60, 0xd3, 0x81, 0x57, 0xd4, 0xb3, 0xcf, 0xef, + 0x16, 0x76, 0x72, 0x1e, 0xe3, 0x12, 0x4b, 0xd4, 0x0c, 0xf1, 0xb0, 0x17, + 0x68, 0xfe, 0xa7, 0xfa, 0xa2, 0x0d, 0x11, 0xaf, 0x89, 0xf9, 0x0a, 0x70, + 0x86, 0xb3, 0x90, 0x52, 0x70, 0x32, 0x80, 0x78, 0xa5, 0x40, 0xea, 0x12, + 0x0c, 0x2d, 0xba, 0x48, 0x6a, 0x26, 0x67, 0xd6, 0x71, 0x29, 0x49, 0xe2, + 0x01, 0x3b, 0x01, 0x25, 0x71, 0x14, 0xc6, 0xb2, 0xf0, 0x99, 0x3a, 0x64, + 0x36, 0xc8, 0x43, 0xc4, 0xa6, 0xcf, 0x6b, 0x12, 0x84, 0x8f, 0x49, 0x60, + 0xe3, 0xb2, 0x69, 0x4c, 0x49, 0xca, 0x5d, 0xcf, 0x05, 0xca, 0xd9, 0xca, + 0x89, 0x30, 0xb5, 0x8a, 0x91, 0x13, 0x14, 0xe3, 0x08, 0x3a, 0x30, 0x4e, + 0xcc, 0xa8, 0x32, 0x9f, 0x23, 0x50, 0xaa, 0xb2, 0xe4, 0x82, 0x59, 0x00, + 0xd4, 0xab, 0x33, 0x25, 0xbd, 0x48, 0x14, 0xf1, 0x67, 0x53, 0x68, 0xa6, + 0xf2, 0x39, 0xe9, 0xe6, 0x31, 0xf4, 0x92, 0x71, 0x6a, 0x1c, 0xa4, 0x9b, + 0xca, 0xce, 0x8e, 0x22, 0x54, 0x8a, 0x02, 0xdb, 0x9a, 0x46, 0xb2, 0xd9, + 0x0b, 0x89, 0x67, 0x92, 0x64, 0x17, 0xcb, 0xc2, 0xa3, 0x38, 0xb5, 0x11, + 0x12, 0x9b, 0xa7, 0x0a, 0x8d, 0x80, 0xa1, 0x2c, 0xc1, 0x66, 0x2f, 0xc4, + 0xb1, 0xc0, 0x02, 0xe9, 0x9c, 0x69, 0xba, 0x40, 0x1c, 0x24, 0x9a, 0x0e, + 0x0b, 0x84, 0x48, 0x25, 0x90, 0x9b, 0x10, 0x7c, 0x24, 0x50, 0x38, 0x8e, + 0x2d, 0x68, 0x22, 0x92, 0x41, 0x98, 0xcd, 0x2c, 0xcc, 0xe7, 0x22, 0x42, + 0x44, 0x8e, 0x03, 0xa1, 0xd3, 0x58, 0x70, 0xda, 0x95, 0x82, 0xd7, 0x82, + 0x90, 0x57, 0xa2, 0x28, 0xc2, 0x2e, 0x06, 0x3e, 0x62, 0x15, 0x67, 0x93, + 0xc8, 0xfd, 0xc2, 0x0f, 0x46, 0x46, 0x2d, 0x49, 0xcb, 0x72, 0xd7, 0x23, + 0x01, 0xe0, 0xcc, 0xd4, 0xb7, 0x92, 0x74, 0xcc, 0xcb, 0x89, 0xb2, 0x36, + 0xae, 0x2f, 0xee, 0x84, 0x20, 0x8e, 0xd6, 0xee, 0x23, 0x90, 0xf2, 0xe3, + 0x22, 0xc6, 0x9a, 0x6a, 0x7a, 0x1a, 0x59, 0xf9, 0xe1, 0x92, 0x78, 0xc8, + 0x92, 0x14, 0x58, 0xa6, 0x4b, 0xd9, 0x36, 0x31, 0x38, 0x46, 0xd9, 0xae, + 0x81, 0x76, 0xa0, 0x54, 0xd4, 0xc7, 0x7a, 0xe2, 0x6b, 0x43, 0x2a, 0x54, + 0x30, 0xb8, 0x94, 0x4c, 0x4d, 0x4f, 0x78, 0xe4, 0xab, 0xe6, 0xa3, 0xc0, + 0xb9, 0x41, 0x1d, 0xd2, 0xdd, 0x4b, 0x07, 0x13, 0x93, 0x93, 0x86, 0x48, + 0x60, 0x64, 0x91, 0x24, 0x95, 0x16, 0x4e, 0xb8, 0x12, 0xa3, 0x04, 0x38, + 0x5c, 0x81, 0x9b, 0x4b, 0xd8, 0xbc, 0x75, 0x04, 0xa1, 0x7d, 0x1a, 0x20, + 0x45, 0x20, 0x24, 0x39, 0x8b, 0xe4, 0x12, 0x51, 0x2b, 0x17, 0x12, 0x29, + 0xc9, 0x8c, 0x00, 0x8e, 0x02, 0x0e, 0x3b, 0x00, 0xbf, 0x84, 0x3f, 0x4a, + 0x01, 0x60, 0x05, 0xf1, 0xc5, 0xc0, 0x20, 0x28, 0x8d, 0xde, 0x8d, 0x44, + 0x4c, 0x0e, 0x78, 0x30, 0xd8, 0xc0, 0xb6, 0xa4, 0x74, 0x68, 0x36, 0xec, + 0xca, 0xb2, 0x32, 0x28, 0xf0, 0xc3, 0x43, 0x28, 0x4e, 0x57, 0x35, 0xc6, + 0x87, 0x72, 0x23, 0xa5, 0xe6, 0xa3, 0x64, 0x43, 0x73, 0x7c, 0x75, 0x3b, + 0x04, 0x87, 0x40, 0x26, 0x60, 0x67, 0x2e, 0x05, 0xc0, 0x23, 0x96, 0x2f, + 0x03, 0x68, 0xc4, 0x49, 0xd2, 0x23, 0xc1, 0x46, 0x53, 0x57, 0xdc, 0x33, + 0x22, 0x57, 0x8a, 0xb0, 0x12, 0x0b, 0xcf, 0x07, 0x92, 0x36, 0x83, 0x02, + 0x5d, 0x2b, 0xd0, 0x23, 0xff, 0x00, 0xc9, 0x1b, 0x2f, 0x14, 0x3a, 0x63, + 0x60, 0x51, 0x24, 0x05, 0xf0, 0xc6, 0x13, 0x4c, 0xae, 0xa6, 0xcd, 0x07, + 0x6f, 0x21, 0x11, 0xbe, 0xf5, 0x6c, 0x45, 0x5d, 0xb0, 0x8c, 0x70, 0xc5, + 0xcd, 0xce, 0xde, 0x59, 0x99, 0x9d, 0x90, 0x50, 0xc3, 0x10, 0x62, 0x29, + 0xd8, 0x80, 0x7c, 0x33, 0x68, 0x44, 0x81, 0xa0, 0x99, 0xae, 0x9e, 0x4c, + 0x14, 0xcc, 0xab, 0x47, 0x00, 0xa3, 0x84, 0x99, 0x09, 0x8a, 0xd2, 0x84, + 0x59, 0x0c, 0x8e, 0x15, 0x52, 0x3d, 0x4b, 0x61, 0x95, 0x85, 0x84, 0x26, + 0x88, 0x4b, 0x48, 0x49, 0x45, 0x4c, 0xea, 0xfa, 0x2f, 0x1c, 0x56, 0xf7, + 0x44, 0x1a, 0x2f, 0x07, 0x04, 0x66, 0x09, 0x4e, 0x1e, 0x2e, 0x88, 0x60, + 0x04, 0x4a, 0x45, 0x38, 0x26, 0x96, 0x62, 0x20, 0xa3, 0x50, 0x4a, 0x05, + 0x87, 0x31, 0x39, 0x83, 0xb9, 0xa6, 0x02, 0x71, 0x54, 0x3c, 0xb2, 0xd9, + 0x50, 0x19, 0x48, 0xc4, 0x4b, 0x14, 0x77, 0xc9, 0xc0, 0x0a, 0x58, 0xab, + 0x10, 0x02, 0xd4, 0x3c, 0x22, 0xe0, 0x95, 0xc9, 0x32, 0x54, 0xeb, 0xfb, + 0x2d, 0xa6, 0x6b, 0xb3, 0xb3, 0x27, 0x14, 0xd8, 0x59, 0x29, 0xc6, 0xd9, + 0x5a, 0xdd, 0xb5, 0x64, 0xac, 0x96, 0x12, 0xab, 0x39, 0x39, 0xc7, 0x66, + 0x63, 0xf4, 0xe6, 0x5a, 0x05, 0xa1, 0x5b, 0xcb, 0x13, 0x2a, 0xcf, 0xeb, + 0x39, 0xe0, 0x54, 0x2a, 0x62, 0x5f, 0x33, 0x34, 0xca, 0xe2, 0x71, 0x3e, + 0x7a, 0x8e, 0x1c, 0xef, 0xc3, 0x1d, 0x63, 0x71, 0x7f, 0xc4, 0x70, 0xe4, + 0x9a, 0x16, 0xa8, 0x10, 0x03, 0x1b, 0x99, 0x4f, 0xcf, 0x9e, 0x09, 0x19, + 0x0b, 0xa0, 0x9a, 0x21, 0x2b, 0x7f, 0x7a, 0x61, 0x1d, 0x08, 0x5b, 0x24, + 0x03, 0x31, 0xee, 0x37, 0x66, 0x8f, 0x67, 0x31, 0x43, 0x0c, 0xe4, 0x91, + 0x8e, 0xde, 0x83, 0x53, 0xc4, 0x10, 0x2e, 0x07, 0xb5, 0x9d, 0xcc, 0x75, + 0x7f, 0x19, 0x02, 0x83, 0x31, 0x8a, 0x0f, 0x7b, 0x99, 0xd3, 0x78, 0x9b, + 0xa6, 0x1e, 0x1c, 0x96, 0x23, 0x2a, 0xaa, 0xd0, 0xa4, 0xb9, 0xc6, 0x71, + 0x77, 0x04, 0x70, 0x4c, 0x29, 0x09, 0x83, 0xc4, 0xd5, 0x2a, 0xe7, 0x07, + 0x99, 0xc0, 0x2c, 0x9c, 0x0e, 0x58, 0x69, 0x19, 0x80, 0x95, 0x79, 0x46, + 0x66, 0x02, 0xf8, 0x22, 0x0b, 0x21, 0x54, 0x93, 0x4d, 0xb4, 0xc3, 0x05, + 0x11, 0x52, 0xe1, 0xc1, 0x0e, 0x96, 0x50, 0x7c, 0x0a, 0xaa, 0x4e, 0xd8, + 0x20, 0xc4, 0xf1, 0x90, 0x64, 0x43, 0x24, 0x32, 0xcc, 0xe0, 0x2a, 0x14, + 0x95, 0x33, 0x35, 0xc6, 0x60, 0xfa, 0x18, 0xc4, 0x83, 0x2a, 0x2d, 0x2b, + 0x16, 0x8b, 0xdb, 0x6a, 0x40, 0xed, 0x01, 0xb2, 0x04, 0x33, 0x44, 0x18, + 0x26, 0x4c, 0xf2, 0x1d, 0x8e, 0x42, 0x2c, 0xca, 0x44, 0x96, 0x25, 0x56, + 0x4d, 0x42, 0x33, 0x1c, 0x4e, 0x5d, 0x9c, 0xa8, 0x24, 0x19, 0x0a, 0xcc, + 0xcc, 0x88, 0xc6, 0x38, 0xeb, 0x19, 0x6d, 0xe1, 0x66, 0x4d, 0x59, 0x62, + 0x31, 0x16, 0xe3, 0x14, 0x85, 0xa8, 0x23, 0x48, 0x01, 0xe6, 0x49, 0x54, + 0x99, 0x23, 0x92, 0x25, 0x04, 0x51, 0x9e, 0x52, 0x10, 0x0c, 0x11, 0x14, + 0x8a, 0x00, 0xe7, 0x8a, 0xb0, 0x62, 0x87, 0x32, 0xb0, 0x6b, 0xe4, 0x84, + 0x8a, 0x12, 0x04, 0xb3, 0x66, 0x5d, 0x28, 0x25, 0xb0, 0x93, 0xc4, 0x21, + 0xc0, 0x38, 0x58, 0x92, 0xf2, 0x01, 0x90, 0x31, 0x4a, 0x69, 0x59, 0x91, + 0x26, 0x7d, 0x15, 0x96, 0xd0, 0x7f, 0xf0, 0x4e, 0x80, 0x1e, 0xbc, 0x42, + 0x42, 0x82, 0xb1, 0xda, 0x80, 0x0a, 0xc7, 0x26, 0x37, 0x58, 0x20, 0xea, + 0xaf, 0x82, 0x63, 0x6c, 0x5e, 0x4e, 0x41, 0xb2, 0x64, 0x96, 0x9b, 0xc9, + 0x2b, 0x01, 0x04, 0x15, 0x94, 0xd2, 0x62, 0x4a, 0xe1, 0x1b, 0x3c, 0x18, + 0x28, 0x58, 0x00, 0xc8, 0x01, 0x51, 0x33, 0x44, 0x85, 0x91, 0xe5, 0x49, + 0xa8, 0x21, 0xe5, 0xa5, 0xc6, 0x32, 0xc8, 0x64, 0x56, 0xcb, 0xa0, 0x8a, + 0x1a, 0x86, 0x93, 0x91, 0x04, 0x24, 0x84, 0x1b, 0x22, 0xa1, 0x60, 0xcb, + 0x26, 0x48, 0xae, 0x30, 0x65, 0x57, 0x19, 0x15, 0x34, 0x96, 0x05, 0x18, + 0x82, 0xb1, 0x0b, 0x0f, 0x12, 0x54, 0x8e, 0x50, 0x8c, 0x18, 0xb4, 0x37, + 0x75, 0x23, 0x99, 0x0d, 0xbc, 0x4c, 0x20, 0x8b, 0x10, 0x99, 0x99, 0x24, + 0x60, 0x82, 0x04, 0x94, 0x95, 0xf6, 0x48, 0xb4, 0x2c, 0x23, 0x3d, 0xf6, + 0x5c, 0xb0, 0x67, 0x04, 0x4c, 0xcb, 0x32, 0x0a, 0x00, 0x2d, 0xc5, 0xb5, + 0x19, 0x99, 0xab, 0x23, 0x59, 0x8a, 0xe2, 0x42, 0x88, 0x17, 0x00, 0x54, + 0xe0, 0x42, 0xd5, 0x33, 0x52, 0x4b, 0x73, 0xc4, 0x08, 0x8d, 0xa0, 0x70, + 0xc0, 0xb8, 0xd5, 0xac, 0x40, 0x06, 0x22, 0xd9, 0x30, 0x0a, 0xc9, 0x62, + 0x51, 0x12, 0x1a, 0x22, 0x26, 0x34, 0x24, 0xe0, 0x20, 0x50, 0x52, 0x35, + 0xb8, 0x99, 0x6f, 0x30, 0x54, 0x21, 0x12, 0xb1, 0x2f, 0x2d, 0x22, 0x09, + 0x60, 0x78, 0x22, 0x88, 0x81, 0x1f, 0x6c, 0x55, 0xb3, 0x55, 0x2a, 0x82, + 0x12, 0x55, 0xda, 0x49, 0x80, 0xc8, 0xc0, 0x49, 0x50, 0x4f, 0x15, 0x9a, + 0x42, 0x7e, 0x12, 0x83, 0xe3, 0x0b, 0x4c, 0xf0, 0xd3, 0x24, 0x8e, 0x25, + 0x54, 0xae, 0xe9, 0x9e, 0xf3, 0xdf, 0x7c, 0xa8, 0xd8, 0x23, 0x1a, 0x59, + 0xab, 0x46, 0x34, 0xfe, 0x91, 0x14, 0x6f, 0x45, 0x56, 0x7c, 0x3d, 0x97, + 0x19, 0x98, 0x9f, 0xcf, 0x21, 0xc9, 0x52, 0x75, 0x5b, 0x90, 0xce, 0xdf, + 0xfb, 0x14, 0xac, 0x13, 0x29, 0x1f, 0x05, 0x67, 0x24, 0x56, 0xa7, 0xf4, + 0xe6, 0x2c, 0x50, 0x4c, 0x55, 0x8a, 0x65, 0x2f, 0xac, 0xf2, 0x00, 0xc9, + 0xf1, 0x87, 0x0d, 0x77, 0x7d, 0xfe, 0xdc, 0x50, 0x2f, 0x34, 0x6e, 0x12, + 0x3c, 0xce, 0xb6, 0x75, 0x71, 0x3c, 0x94, 0x61, 0x7c, 0xb4, 0x7c, 0x66, + 0xae, 0x2f, 0xc1, 0xc8, 0xd9, 0x2c, 0x96, 0x52, 0x5d, 0xdc, 0x7c, 0xf9, + 0x7c, 0x87, 0x14, 0x33, 0xf1, 0x31, 0x98, 0x5b, 0x25, 0x77, 0x3b, 0xc1, + 0x16, 0xd2, 0x24, 0x48, 0xc8, 0x3e, 0x12, 0x6a, 0x10, 0x9c, 0xd6, 0x7e, + 0xad, 0x40, 0x92, 0x25, 0x94, 0xb9, 0xcb, 0xd9, 0x53, 0x49, 0x85, 0xd0, + 0xf3, 0x2b, 0x40, 0x54, 0x86, 0x72, 0xdc, 0x08, 0x5f, 0xdc, 0xea, 0xf9, + 0x20, 0x19, 0x4b, 0x4b, 0x8a, 0x16, 0xc9, 0xf9, 0x5e, 0xe5, 0x40, 0x38, + 0x0a, 0x1f, 0x4d, 0xbf, 0x58, 0xcc, 0xc3, 0x69, 0x27, 0x88, 0x6e, 0x22, + 0x44, 0xd2, 0x85, 0xf9, 0x23, 0xe3, 0xe7, 0x19, 0xe4, 0x49, 0x21, 0x0d, + 0x05, 0xbd, 0xd4, 0x21, 0x55, 0x82, 0xb3, 0xe3, 0x8a, 0xc6, 0x12, 0x15, + 0x28, 0xcb, 0x8c, 0x47, 0xcc, 0xa9, 0x24, 0x34, 0xf2, 0xf8, 0x29, 0x50, + 0x81, 0x85, 0xcd, 0x4c, 0xaf, 0x9b, 0xd6, 0x58, 0xe3, 0x2b, 0x96, 0xe6, + 0xa6, 0x53, 0x4c, 0x10, 0xcc, 0xb2, 0x10, 0x4c, 0xd4, 0x1c, 0x5c, 0x04, + 0x0a, 0x9d, 0x00, 0x39, 0x1c, 0xaa, 0x08, 0x98, 0xc1, 0x3a, 0xe5, 0x80, + 0x96, 0x01, 0xe5, 0x81, 0x93, 0x4a, 0x1c, 0xf4, 0xc9, 0x87, 0xcd, 0x2f, + 0x66, 0x00, 0x3a, 0xf2, 0x00, 0xb4, 0x32, 0x18, 0xd4, 0x66, 0x25, 0x74, + 0x33, 0x28, 0x84, 0x5f, 0xf2, 0x8d, 0xd9, 0xe9, 0xcc, 0x10, 0x32, 0x7a, + 0x23, 0x30, 0x2d, 0x11, 0x25, 0x83, 0x0b, 0x10, 0x84, 0x90, 0xab, 0xe3, + 0x80, 0x54, 0x30, 0x8b, 0x22, 0x10, 0x18, 0xd0, 0xa0, 0x03, 0x30, 0x17, + 0x74, 0x78, 0x52, 0x49, 0x70, 0xd5, 0x18, 0x6e, 0x45, 0x91, 0x90, 0x18, + 0xc3, 0x8e, 0x4b, 0x0d, 0x4a, 0x62, 0x40, 0x14, 0x5d, 0xdc, 0x1c, 0x01, + 0x58, 0x18, 0xe0, 0x31, 0x96, 0x51, 0x01, 0xec, 0xa4, 0x02, 0x60, 0x6e, + 0xe9, 0x94, 0x87, 0x99, 0x99, 0x1b, 0x91, 0x29, 0x32, 0xac, 0x45, 0x3e, + 0x5a, 0xa2, 0xce, 0x32, 0x84, 0x0c, 0x91, 0x5b, 0x4a, 0xa6, 0x6c, 0x92, + 0x20, 0xd4, 0xc6, 0x17, 0xc2, 0x15, 0xd9, 0x43, 0x65, 0x60, 0x6f, 0x08, + 0xf9, 0x94, 0x25, 0xa9, 0x80, 0x04, 0xb8, 0x99, 0x9b, 0x40, 0x19, 0x80, + 0x1b, 0x83, 0xc5, 0x64, 0xab, 0x99, 0x1c, 0x29, 0xa6, 0xc0, 0x8b, 0x28, + 0x85, 0x1c, 0x40, 0x37, 0xc0, 0x10, 0x30, 0xb8, 0x0b, 0x12, 0x0a, 0xa9, + 0x31, 0x00, 0xc9, 0x75, 0x6c, 0x50, 0xf2, 0x41, 0x2c, 0xb8, 0x47, 0x2a, + 0x71, 0x8d, 0xc1, 0x92, 0xb3, 0x2a, 0x48, 0xe0, 0x0c, 0xc2, 0x19, 0x48, + 0x5c, 0x9a, 0x8a, 0x32, 0x60, 0x23, 0x28, 0xe2, 0x00, 0x08, 0x88, 0xd2, + 0x41, 0x82, 0x64, 0x98, 0x56, 0x64, 0x52, 0x12, 0xda, 0xae, 0x13, 0x50, + 0x5b, 0x9d, 0x7b, 0xe8, 0xd3, 0x82, 0x5c, 0x91, 0xc2, 0x48, 0x11, 0xb6, + 0x52, 0x98, 0x84, 0x80, 0x21, 0x88, 0x61, 0x88, 0x59, 0xdb, 0x0b, 0x73, + 0x39, 0xa1, 0x50, 0xd8, 0x9b, 0xbc, 0x78, 0x4c, 0x70, 0x40, 0x51, 0x50, + 0xbb, 0xc1, 0x51, 0xe0, 0xf3, 0x7d, 0x46, 0xb8, 0xe0, 0x8c, 0x92, 0xd4, + 0xca, 0x13, 0xee, 0xc3, 0x3b, 0x30, 0x62, 0x39, 0x31, 0x6c, 0x54, 0x59, + 0x60, 0x13, 0x69, 0x73, 0x97, 0xc3, 0x18, 0xe0, 0x21, 0x7d, 0x91, 0xac, + 0x1a, 0xa1, 0x1f, 0xd3, 0x3b, 0x4e, 0x2c, 0x8b, 0xbd, 0x0b, 0x2c, 0xde, + 0x27, 0x3e, 0x33, 0xbe, 0x3c, 0x8c, 0xd6, 0x47, 0x69, 0xdc, 0x3a, 0xac, + 0xb1, 0xf7, 0x31, 0x41, 0x22, 0x64, 0x64, 0x23, 0x2a, 0x7c, 0x7a, 0xcf, + 0x7b, 0xe3, 0xb9, 0x4c, 0xcd, 0x5c, 0x4c, 0x2c, 0xc1, 0x55, 0x1e, 0xaf, + 0xd4, 0xc0, 0x90, 0xc7, 0xd2, 0x98, 0xde, 0x34, 0x38, 0x8f, 0x39, 0xe0, + 0x46, 0x19, 0xa2, 0xd8, 0xbf, 0xd3, 0x1f, 0xbc, 0x06, 0x21, 0xe9, 0x9a, + 0x8b, 0x68, 0xd5, 0x31, 0xf3, 0xef, 0xa0, 0xc3, 0x70, 0xe0, 0x61, 0x17, + 0xe6, 0xc8, 0x16, 0xcd, 0x5d, 0xb2, 0xe7, 0x93, 0x21, 0x3a, 0x04, 0xad, + 0x6a, 0x10, 0x64, 0xcc, 0x4b, 0x3a, 0xed, 0x16, 0x43, 0x08, 0x88, 0x86, + 0xc6, 0x7c, 0x8c, 0xd7, 0xb9, 0xd7, 0x10, 0x83, 0x9a, 0x30, 0xc3, 0x0d, + 0xc4, 0xdc, 0x4a, 0x5d, 0x9a, 0xb0, 0x86, 0xcc, 0x1a, 0xd1, 0x31, 0x98, + 0x10, 0x30, 0x12, 0x63, 0x3a, 0xe0, 0xc5, 0x08, 0x26, 0x74, 0x21, 0x86, + 0xf5, 0x33, 0x26, 0xe6, 0x36, 0x8c, 0x4c, 0x40, 0x16, 0x49, 0xb5, 0x26, + 0x2a, 0xc2, 0xdf, 0x32, 0x55, 0x0f, 0x1c, 0x01, 0x64, 0x25, 0xc4, 0x2c, + 0xc0, 0xfd, 0x4d, 0x44, 0xf7, 0xd3, 0x14, 0x43, 0x90, 0x4b, 0x52, 0xa5, + 0x74, 0xc5, 0xfa, 0x51, 0xd0, 0x12, 0xcc, 0x20, 0xb9, 0x6c, 0x3a, 0x87, + 0xdc, 0xd2, 0xd4, 0x12, 0x54, 0xaa, 0x04, 0x82, 0xc2, 0xd8, 0x40, 0x2b, + 0x3b, 0x61, 0xa1, 0x63, 0x0c, 0x51, 0x33, 0x22, 0xc4, 0x60, 0x84, 0x04, + 0xfb, 0x89, 0xc9, 0x2c, 0x95, 0x30, 0xb3, 0x5c, 0x67, 0x52, 0x6a, 0x25, + 0x38, 0x37, 0x07, 0x51, 0x23, 0x2a, 0x4b, 0xd4, 0x71, 0xa5, 0x32, 0xa0, + 0x45, 0x35, 0xa2, 0xe0, 0x87, 0x40, 0x1f, 0x99, 0x25, 0x24, 0x84, 0xb2, + 0xd0, 0x14, 0x5a, 0x02, 0xa7, 0xfc, 0x8e, 0x76, 0x12, 0x2c, 0x2e, 0x29, + 0x43, 0x11, 0xd2, 0xe9, 0x1d, 0x43, 0x80, 0xb7, 0x82, 0x0c, 0x0d, 0x59, + 0xa8, 0x4e, 0x26, 0xd8, 0x26, 0xb8, 0xe7, 0x09, 0x90, 0x20, 0x9b, 0x00, + 0xa8, 0x06, 0xf1, 0xec, 0x63, 0x80, 0x19, 0x10, 0x17, 0x93, 0xa9, 0x20, + 0x9b, 0xed, 0x01, 0x5a, 0x89, 0xe2, 0x42, 0x32, 0x02, 0xa6, 0x24, 0x88, + 0x82, 0x05, 0x3a, 0x3b, 0x81, 0x82, 0x44, 0x33, 0x04, 0x45, 0x25, 0x19, + 0x4c, 0x0c, 0x40, 0xc3, 0x6c, 0x09, 0x1d, 0xcf, 0x13, 0x63, 0x24, 0x81, + 0x04, 0x5a, 0x65, 0x99, 0x30, 0x84, 0xc8, 0x43, 0xdf, 0x25, 0x84, 0x51, + 0x95, 0x98, 0x31, 0x2c, 0xa5, 0x33, 0xf2, 0x66, 0x77, 0xc9, 0x2a, 0x30, + 0x1d, 0x23, 0x6d, 0x59, 0x58, 0x63, 0xb9, 0xc5, 0x22, 0x28, 0x4c, 0xda, + 0x90, 0x4b, 0x86, 0x14, 0x52, 0x46, 0x26, 0x0c, 0x66, 0x55, 0x58, 0x30, + 0x54, 0xa9, 0x21, 0x0a, 0xce, 0x0d, 0x08, 0x2a, 0x74, 0x71, 0x19, 0x55, + 0xda, 0x6c, 0xa0, 0x32, 0xf6, 0x42, 0x97, 0xba, 0x22, 0x60, 0x44, 0x26, + 0xa9, 0xa6, 0x27, 0xc3, 0x42, 0x88, 0x80, 0xb0, 0x13, 0x18, 0x5e, 0x29, + 0x25, 0x77, 0x62, 0x62, 0x82, 0x22, 0xb0, 0xaf, 0x91, 0x48, 0xc7, 0x21, + 0x31, 0x65, 0xe5, 0xc9, 0x0e, 0x8c, 0x04, 0xd9, 0x95, 0x9d, 0x23, 0x28, + 0x02, 0x46, 0x01, 0x66, 0x97, 0x0a, 0x77, 0x29, 0xd2, 0x9e, 0xf8, 0x44, + 0x43, 0x2c, 0xc2, 0x54, 0x07, 0xb5, 0xb3, 0x84, 0x08, 0xb2, 0x50, 0xe4, + 0x09, 0x08, 0xd0, 0x84, 0xe6, 0x59, 0x93, 0x05, 0xda, 0xae, 0x68, 0x33, + 0xc6, 0x99, 0x85, 0x42, 0x41, 0x30, 0xe4, 0x3a, 0xdc, 0x3d, 0x40, 0x4e, + 0x39, 0x79, 0x31, 0x21, 0x92, 0x71, 0x8f, 0x1e, 0xa7, 0x3f, 0x95, 0x32, + 0x13, 0x64, 0xac, 0x6e, 0x65, 0x24, 0xc4, 0x9d, 0x4f, 0x9e, 0xf9, 0x14, + 0x8d, 0x8c, 0xfc, 0x79, 0x2e, 0x6b, 0x35, 0x3a, 0x46, 0xb9, 0x34, 0x22, + 0xa4, 0xeb, 0x50, 0xc6, 0x6a, 0x7e, 0xb5, 0xbe, 0x4e, 0x12, 0xcb, 0x42, + 0xa4, 0xfd, 0x44, 0x95, 0x8f, 0x77, 0x1c, 0xc4, 0x31, 0x26, 0x9c, 0xee, + 0x49, 0xb9, 0x31, 0xea, 0x72, 0xc7, 0x16, 0x81, 0xc6, 0x22, 0x62, 0x22, + 0xf3, 0xfa, 0xec, 0x63, 0x93, 0x83, 0xc4, 0x04, 0xea, 0x89, 0x96, 0xe2, + 0x27, 0x5d, 0xc9, 0xc7, 0x21, 0x5a, 0x4c, 0x04, 0xba, 0xb8, 0x1c, 0xde, + 0x8f, 0x11, 0x7c, 0x75, 0x21, 0xa8, 0xfc, 0xe6, 0x14, 0xbd, 0x44, 0xfa, + 0xcc, 0x27, 0x24, 0x21, 0x7c, 0x43, 0x8c, 0x7b, 0x94, 0xfc, 0xc1, 0x07, + 0x5c, 0x80, 0x48, 0x61, 0x90, 0x64, 0x89, 0x89, 0x9a, 0x77, 0xec, 0xfb, + 0x92, 0x01, 0x99, 0x88, 0x25, 0x35, 0x78, 0x86, 0x0d, 0x5b, 0x1e, 0xdd, + 0x15, 0x84, 0x84, 0x6a, 0xb2, 0x65, 0x55, 0xe8, 0x0c, 0x43, 0x81, 0x32, + 0xf1, 0x02, 0x6d, 0x31, 0x48, 0x98, 0x58, 0xa6, 0x2a, 0x06, 0x0a, 0x9a, + 0x2c, 0xe1, 0xd5, 0xc5, 0x91, 0x0c, 0xe8, 0xe9, 0x89, 0x8d, 0x07, 0x79, + 0xa9, 0x74, 0x55, 0x98, 0x96, 0x8c, 0xc9, 0x2c, 0x08, 0x01, 0x8b, 0x5c, + 0xcd, 0x4d, 0x11, 0x00, 0xdc, 0x62, 0x57, 0x31, 0x24, 0x7d, 0xf7, 0x11, + 0xc5, 0x12, 0x4f, 0xa9, 0x76, 0xc6, 0x25, 0x2d, 0x77, 0xe1, 0xbc, 0x8a, + 0x4b, 0xcc, 0x27, 0xea, 0x8f, 0x58, 0x1a, 0xce, 0x2f, 0x8b, 0x52, 0xd0, + 0xc9, 0x15, 0xf4, 0x46, 0xe6, 0x73, 0x2a, 0x63, 0x8e, 0x82, 0x53, 0x80, + 0x84, 0xc4, 0xc9, 0x20, 0x4b, 0xdb, 0x6f, 0x76, 0x32, 0x70, 0xd8, 0x09, + 0x3e, 0x9c, 0x33, 0xe2, 0x27, 0xe5, 0x79, 0x15, 0x58, 0x58, 0x01, 0x41, + 0x0d, 0xa0, 0x5d, 0x49, 0x08, 0xae, 0x34, 0xac, 0x86, 0xc1, 0x5c, 0xe0, + 0xc1, 0x65, 0xad, 0x4d, 0xff, 0x00, 0x94, 0x00, 0x66, 0x68, 0xad, 0xe6, + 0xf7, 0x11, 0xbe, 0xf5, 0xcf, 0x81, 0x11, 0x6d, 0x50, 0xfa, 0x98, 0x92, + 0x31, 0x32, 0x1c, 0x94, 0xc0, 0x08, 0x91, 0x04, 0x50, 0x64, 0xf7, 0x6b, + 0x1a, 0x0a, 0xd4, 0x72, 0x5a, 0x36, 0x08, 0xdc, 0xb2, 0x24, 0xc9, 0x2c, + 0x01, 0xae, 0xae, 0x0c, 0xf1, 0x05, 0x08, 0x09, 0x4a, 0x0c, 0xb3, 0x2c, + 0x05, 0x1a, 0x1f, 0xc0, 0x9c, 0x16, 0x92, 0x30, 0xb4, 0x68, 0x4c, 0x29, + 0x58, 0x3c, 0x05, 0x82, 0xa5, 0xb1, 0x60, 0x02, 0xc4, 0x00, 0xa3, 0x22, + 0x16, 0xc2, 0xd1, 0xa9, 0x26, 0x80, 0x42, 0x44, 0x06, 0xd2, 0xb8, 0x48, + 0x4e, 0xa0, 0x06, 0xf2, 0xc0, 0xc8, 0xf5, 0xc4, 0x24, 0x48, 0x51, 0x42, + 0x04, 0xa7, 0x50, 0x92, 0xda, 0xae, 0x9c, 0x2c, 0xf9, 0x18, 0x19, 0xb4, + 0xad, 0x49, 0x61, 0x21, 0x8c, 0x54, 0x23, 0x53, 0x68, 0x67, 0x6a, 0x13, + 0x30, 0x16, 0x40, 0xa2, 0x08, 0x98, 0x9c, 0x84, 0x54, 0x1c, 0x16, 0x0b, + 0x8a, 0x25, 0x37, 0x2b, 0x0b, 0x38, 0xd0, 0x61, 0xfb, 0xb4, 0xa2, 0x0b, + 0x26, 0x66, 0xc6, 0x0a, 0xa6, 0x88, 0x27, 0xab, 0xf1, 0xc5, 0x85, 0xc9, + 0x62, 0xf7, 0x94, 0x24, 0x93, 0x98, 0x90, 0x2c, 0x68, 0x99, 0x38, 0x51, + 0x84, 0xb3, 0x08, 0xdc, 0x18, 0x50, 0xb1, 0x45, 0xa8, 0xf2, 0x70, 0x04, + 0x62, 0x14, 0x65, 0x92, 0xa3, 0x05, 0xc4, 0x42, 0xea, 0xde, 0x58, 0x52, + 0x26, 0x08, 0x32, 0xa5, 0x8a, 0x76, 0xea, 0xfa, 0x0e, 0x4f, 0x64, 0xca, + 0x74, 0xe4, 0x80, 0x12, 0x16, 0xa6, 0x5f, 0x34, 0xb1, 0x1c, 0xb8, 0x97, + 0x1b, 0x04, 0xb6, 0x61, 0x5d, 0x4c, 0x56, 0x2b, 0x3a, 0xe4, 0x11, 0x10, + 0xcc, 0x2b, 0x04, 0x19, 0x62, 0x42, 0x2b, 0x05, 0xcc, 0xe7, 0x6d, 0x4e, + 0x21, 0x96, 0x8c, 0x7e, 0xe4, 0x4e, 0xba, 0x8b, 0x67, 0x98, 0xa1, 0x88, + 0x87, 0xb4, 0xd9, 0x31, 0x84, 0xc7, 0xed, 0x5c, 0xa8, 0x56, 0x58, 0x1c, + 0xb3, 0xff, 0x00, 0x2a, 0xe6, 0x33, 0x37, 0x1c, 0x89, 0x87, 0x64, 0xb2, + 0x57, 0xa9, 0x82, 0x62, 0x58, 0x8e, 0xec, 0x9e, 0x41, 0xb2, 0x66, 0x66, + 0x92, 0x7f, 0x04, 0x1f, 0xd3, 0x90, 0xc2, 0xb0, 0xf9, 0xee, 0x25, 0x64, + 0x65, 0xbc, 0x7b, 0x63, 0x3c, 0x52, 0x0b, 0x4b, 0x3e, 0x03, 0xad, 0xe4, + 0x95, 0xea, 0x9e, 0x3a, 0x05, 0x71, 0x8c, 0xc7, 0xbb, 0x98, 0xbf, 0x9f, + 0x95, 0x5c, 0xd5, 0x84, 0x2d, 0xbf, 0x33, 0x87, 0x66, 0xaf, 0x07, 0x0d, + 0x07, 0xc1, 0x3a, 0x0c, 0x37, 0x3e, 0x31, 0x79, 0xef, 0x84, 0x51, 0x21, + 0x10, 0xd5, 0x5e, 0x71, 0x15, 0x35, 0x8e, 0xa8, 0xc9, 0xc1, 0x4c, 0x08, + 0x67, 0x1a, 0x4b, 0x2a, 0xaa, 0xbe, 0x1b, 0xb8, 0x17, 0x20, 0x00, 0x24, + 0x39, 0xcc, 0x30, 0x2c, 0xb7, 0xa2, 0x67, 0xd2, 0x66, 0x50, 0xd8, 0x14, + 0x62, 0x70, 0x3a, 0xd4, 0xfe, 0xb1, 0xd5, 0x62, 0x59, 0xdd, 0x8d, 0x77, + 0xe2, 0x49, 0x22, 0x22, 0x5f, 0x79, 0xe2, 0x6c, 0x84, 0x04, 0xe6, 0xc3, + 0xf7, 0x83, 0x13, 0xdd, 0x46, 0x78, 0x2e, 0x14, 0x05, 0x8c, 0xdf, 0x50, + 0x83, 0x1e, 0xd9, 0x92, 0x98, 0xd7, 0x10, 0x34, 0x2d, 0xb0, 0x62, 0x32, + 0x14, 0x97, 0x64, 0xea, 0xb7, 0xae, 0x14, 0xc9, 0x65, 0x17, 0x8b, 0xc6, + 0xca, 0x2d, 0xf3, 0x5d, 0x47, 0x24, 0x29, 0x1b, 0x54, 0x12, 0x2d, 0x94, + 0x33, 0xfa, 0x1f, 0x35, 0xc0, 0x04, 0x11, 0x93, 0x04, 0xba, 0x82, 0x5a, + 0x64, 0xa8, 0x90, 0x29, 0xcc, 0xf1, 0x92, 0x44, 0xbb, 0xdc, 0xf5, 0x75, + 0xe6, 0x77, 0x82, 0xa2, 0x39, 0x3b, 0xfc, 0x6c, 0xac, 0x7d, 0x3d, 0x4c, + 0x7b, 0x22, 0x67, 0x80, 0x94, 0xed, 0x8c, 0x0d, 0x32, 0x1a, 0x8a, 0x3d, + 0x79, 0xff, 0x00, 0x37, 0x8c, 0x32, 0x80, 0xd4, 0xb4, 0xde, 0x73, 0xd7, + 0xcd, 0x3c, 0x40, 0x43, 0x0c, 0x8d, 0x44, 0xf7, 0x9b, 0x31, 0x11, 0x73, + 0xd0, 0x0a, 0x41, 0x86, 0x86, 0x26, 0x02, 0x22, 0x66, 0xd8, 0x7a, 0x46, + 0x23, 0x08, 0x58, 0xec, 0x90, 0x84, 0xe6, 0xe5, 0x8c, 0x4d, 0x06, 0xc4, + 0x79, 0x59, 0x73, 0xd0, 0x64, 0x24, 0x09, 0x11, 0xda, 0x21, 0x2e, 0x21, + 0xb9, 0x87, 0x83, 0x0b, 0x62, 0x60, 0xd8, 0x61, 0x64, 0x31, 0x14, 0x0c, + 0xac, 0x89, 0x3a, 0x18, 0x20, 0x25, 0x51, 0x6c, 0x66, 0x25, 0x12, 0xba, + 0x22, 0x12, 0xdb, 0xad, 0x70, 0xa1, 0x2e, 0x59, 0x9f, 0x28, 0xad, 0x12, + 0x5f, 0x5e, 0xe2, 0x23, 0x88, 0x20, 0x89, 0x68, 0x99, 0x66, 0xaa, 0x8c, + 0x48, 0xf8, 0x64, 0x83, 0x08, 0xf3, 0x08, 0x92, 0x95, 0x04, 0x13, 0x2c, + 0xb9, 0x51, 0x18, 0x82, 0xf3, 0xdf, 0x15, 0x46, 0x92, 0x22, 0x96, 0x28, + 0xd1, 0x02, 0x4d, 0x18, 0x91, 0x89, 0xbf, 0x33, 0x94, 0xc8, 0xee, 0x0a, + 0x08, 0xa4, 0x90, 0xb7, 0x65, 0x8e, 0xc3, 0x8d, 0x09, 0x1c, 0xa0, 0x17, + 0x41, 0x9b, 0x3a, 0x59, 0x20, 0x81, 0x23, 0x32, 0x26, 0x14, 0x14, 0x65, + 0x00, 0xb6, 0xee, 0x1c, 0x23, 0x3b, 0x89, 0x0e, 0x64, 0xa0, 0x90, 0x5e, + 0x67, 0x69, 0xe6, 0x2b, 0xef, 0x8c, 0x19, 0x24, 0x88, 0xc8, 0xe3, 0x09, + 0x0f, 0x89, 0xd3, 0x3f, 0x85, 0x20, 0x08, 0x92, 0x8b, 0x0a, 0xa4, 0xa9, + 0x33, 0x35, 0x12, 0x01, 0x5e, 0x71, 0xcb, 0x89, 0x36, 0x40, 0xc3, 0x03, + 0x78, 0xc4, 0xac, 0x43, 0x7e, 0x79, 0x83, 0xb4, 0x16, 0xe4, 0x6e, 0xe1, + 0xf0, 0xb7, 0x45, 0xe7, 0x8c, 0xe3, 0xbe, 0xa1, 0x20, 0xa2, 0x4e, 0xef, + 0xc4, 0x74, 0xc7, 0x21, 0x28, 0xd9, 0x4d, 0x10, 0xc6, 0x13, 0xb1, 0xc9, + 0x9e, 0xec, 0xe0, 0x0a, 0xad, 0x27, 0xcc, 0x84, 0x29, 0x9e, 0xef, 0x3a, + 0xd5, 0xb4, 0x6d, 0x27, 0x86, 0xbc, 0xf7, 0x31, 0xb3, 0x05, 0xc8, 0x92, + 0xd9, 0x72, 0x9a, 0x7c, 0xa7, 0xf7, 0x7b, 0xc6, 0xf8, 0xb0, 0x26, 0x22, + 0x3b, 0x98, 0x03, 0xab, 0xeb, 0x75, 0x1e, 0xb9, 0x38, 0x13, 0x7d, 0x31, + 0xf7, 0x3e, 0x26, 0x6e, 0xe4, 0x65, 0x4e, 0x4e, 0x92, 0xd9, 0x9b, 0x9c, + 0x5c, 0x55, 0x6b, 0x50, 0xd7, 0x93, 0x84, 0x04, 0x0e, 0x9c, 0xb0, 0xcc, + 0x8b, 0x6f, 0x5d, 0xe7, 0xce, 0x63, 0xb4, 0xdc, 0x04, 0xa9, 0x18, 0xba, + 0x23, 0xc7, 0x59, 0xf5, 0xc8, 0x62, 0xe0, 0x9d, 0xc9, 0x69, 0xef, 0xee, + 0x7e, 0x32, 0x71, 0x11, 0x87, 0xe5, 0x8a, 0xaa, 0xb9, 0x90, 0xca, 0x0f, + 0xeb, 0x25, 0x92, 0x98, 0x83, 0x26, 0x3a, 0x0e, 0xb1, 0xa8, 0xf7, 0x53, + 0xc8, 0x95, 0x8a, 0x6f, 0x17, 0x31, 0x91, 0x9a, 0xfb, 0x3d, 0xec, 0x20, + 0x97, 0x66, 0x32, 0xfb, 0x86, 0x8f, 0x8f, 0xbd, 0x71, 0xb6, 0x77, 0x60, + 0x98, 0x88, 0x8c, 0x85, 0x93, 0x0a, 0x6b, 0x83, 0xd8, 0x56, 0x0d, 0xf8, + 0x96, 0x64, 0x65, 0x82, 0x2f, 0x61, 0x16, 0xc2, 0x93, 0xd4, 0xeb, 0x6c, + 0x03, 0x4f, 0x7d, 0xf9, 0xaa, 0x79, 0x82, 0x62, 0xe1, 0x7d, 0x35, 0xd9, + 0xb3, 0xa5, 0xb5, 0xe4, 0x50, 0x89, 0xb5, 0xcc, 0xc4, 0x66, 0xa6, 0x67, + 0xfb, 0x6a, 0xf2, 0x50, 0x43, 0xb1, 0x0f, 0x4c, 0xc8, 0xd1, 0xdb, 0x26, + 0x33, 0x71, 0x5c, 0x06, 0x81, 0x89, 0x96, 0x3a, 0x8d, 0x4a, 0xc4, 0x1d, + 0x4e, 0x26, 0x66, 0xa6, 0x01, 0xa4, 0xc2, 0xc4, 0x26, 0xca, 0xcf, 0x78, + 0x0c, 0x37, 0x97, 0x99, 0x2d, 0xcd, 0xca, 0xa1, 0xaa, 0x08, 0x94, 0x19, + 0x7a, 0x93, 0x55, 0xc5, 0x25, 0xd6, 0x92, 0xa6, 0x89, 0xce, 0xbf, 0xce, + 0x35, 0x53, 0x31, 0x33, 0x6a, 0x24, 0xfd, 0x21, 0xd4, 0xb4, 0xd4, 0x64, + 0x41, 0x60, 0x9a, 0xa6, 0xd4, 0x21, 0x29, 0x51, 0x89, 0x24, 0x1e, 0x1d, + 0xaa, 0x19, 0x02, 0xf1, 0x31, 0x18, 0x61, 0xce, 0x4a, 0xe9, 0x5b, 0x20, + 0x9a, 0x2c, 0x5b, 0x31, 0x29, 0x21, 0x05, 0x32, 0x14, 0xa9, 0x6a, 0x74, + 0x16, 0xb2, 0x27, 0xc9, 0x98, 0x9a, 0x81, 0x04, 0x19, 0x99, 0xcf, 0x2c, + 0x61, 0x8a, 0x06, 0x01, 0x89, 0x17, 0x14, 0xce, 0xda, 0x03, 0x18, 0x78, + 0x11, 0xb9, 0xee, 0xc4, 0x29, 0x40, 0x4f, 0x62, 0x61, 0x86, 0x7c, 0x71, + 0x7a, 0xb4, 0x13, 0x73, 0x98, 0x02, 0x08, 0xbc, 0xe3, 0xc2, 0x35, 0x65, + 0x9b, 0x10, 0x00, 0x84, 0xe7, 0x29, 0x74, 0xd5, 0xcc, 0xb4, 0xa5, 0xac, + 0xae, 0xc9, 0x04, 0x33, 0x2f, 0x9a, 0xa0, 0x16, 0xcd, 0x26, 0x9a, 0x46, + 0xd6, 0x1b, 0x92, 0x4a, 0x22, 0x84, 0x92, 0x2a, 0x6c, 0xb1, 0x03, 0x3c, + 0xac, 0x9b, 0x2b, 0x34, 0x60, 0x68, 0x45, 0x8a, 0x54, 0x12, 0x4b, 0x86, + 0x07, 0x8c, 0x88, 0x03, 0x2b, 0x2d, 0x53, 0x39, 0x9b, 0x99, 0x88, 0xac, + 0xe1, 0x12, 0x72, 0x75, 0xa0, 0x9b, 0x4b, 0x02, 0x15, 0x66, 0x1a, 0x12, + 0x7d, 0x82, 0x26, 0x50, 0x02, 0x06, 0x3c, 0xcc, 0x90, 0x25, 0x2d, 0xcc, + 0x54, 0x5a, 0x11, 0x2f, 0x04, 0x88, 0x99, 0x68, 0x4d, 0xe1, 0x87, 0x30, + 0x1d, 0x2c, 0x58, 0x99, 0x61, 0x52, 0xc9, 0x20, 0x95, 0x2f, 0x62, 0x45, + 0xc3, 0xad, 0x17, 0x31, 0x04, 0x9c, 0xba, 0xcc, 0xc8, 0xb5, 0x50, 0x18, + 0x91, 0x0a, 0xe8, 0x7a, 0xc4, 0xc9, 0xe4, 0x04, 0x25, 0xe0, 0x88, 0x09, + 0x9e, 0x89, 0x03, 0x49, 0x52, 0xbc, 0x81, 0x89, 0xb5, 0x99, 0x62, 0x2a, + 0x1c, 0x9e, 0x35, 0xf9, 0x78, 0xb3, 0x22, 0xac, 0x35, 0x23, 0xfc, 0xc1, + 0x6e, 0x92, 0x76, 0x4b, 0x20, 0xc2, 0x69, 0x81, 0x59, 0x00, 0x70, 0x99, + 0x89, 0x22, 0x31, 0x0f, 0x18, 0x86, 0x55, 0xa6, 0x61, 0x1f, 0x51, 0x2c, + 0x78, 0x95, 0xf1, 0xd7, 0x20, 0x0c, 0x4c, 0x80, 0x64, 0xc3, 0x7e, 0x98, + 0x82, 0x01, 0x9e, 0xfa, 0xe0, 0x0c, 0xa6, 0x0d, 0x5b, 0x27, 0xe9, 0xfb, + 0xce, 0xb9, 0x5c, 0xce, 0x6b, 0x3b, 0x8b, 0x64, 0x88, 0xb4, 0x77, 0x27, + 0x44, 0xf2, 0x50, 0xd7, 0x64, 0xef, 0xc4, 0xc7, 0xe2, 0xe4, 0x38, 0xf1, + 0xd1, 0x89, 0x9d, 0x17, 0x8d, 0x31, 0xfc, 0xce, 0x78, 0x46, 0x53, 0x32, + 0x2c, 0xce, 0x3e, 0x46, 0x1a, 0xae, 0x25, 0x43, 0x83, 0x37, 0x36, 0x8d, + 0x57, 0xe1, 0xd1, 0xee, 0x05, 0x6d, 0xd0, 0xd6, 0xab, 0x04, 0x51, 0x15, + 0x77, 0x8a, 0x9e, 0x53, 0x23, 0x06, 0x2c, 0x37, 0x9a, 0x77, 0xee, 0x1f, + 0x25, 0x70, 0x58, 0x40, 0x4b, 0xe6, 0x3d, 0xd3, 0x45, 0xb8, 0x33, 0xea, + 0xb8, 0x90, 0xab, 0x96, 0x55, 0x89, 0x95, 0xc4, 0xc7, 0xc4, 0x4b, 0x1e, + 0xf1, 0x04, 0x25, 0x90, 0x44, 0x31, 0x05, 0xc2, 0xc6, 0x1a, 0x76, 0xde, + 0x4e, 0x24, 0x6c, 0x46, 0x16, 0xe3, 0xd1, 0x37, 0x01, 0xe7, 0xe6, 0x39, + 0x51, 0x2a, 0x12, 0xac, 0x89, 0xfb, 0x01, 0x9c, 0xcb, 0x3d, 0xd1, 0x7c, + 0x12, 0x6c, 0x9c, 0xcd, 0xef, 0x77, 0x01, 0x76, 0x06, 0x33, 0xbe, 0x21, + 0x64, 0x55, 0x3d, 0x3d, 0xc4, 0x74, 0xbc, 0x43, 0x16, 0xf0, 0x07, 0x09, + 0x22, 0xa5, 0x0f, 0x38, 0x1f, 0xc4, 0x6f, 0x8a, 0x39, 0x3a, 0x22, 0x71, + 0x98, 0x8d, 0xe3, 0xf5, 0xf3, 0x56, 0x11, 0x35, 0x6c, 0xc4, 0xc7, 0x89, + 0x62, 0x7d, 0x4e, 0xd8, 0xe4, 0xb6, 0xa2, 0x72, 0xc6, 0x42, 0xe8, 0xa6, + 0x6a, 0xf3, 0x21, 0xc7, 0x5d, 0x58, 0x32, 0xfe, 0x28, 0xeb, 0xa9, 0x11, + 0x8e, 0xbf, 0xc9, 0x57, 0x3b, 0xfb, 0xf7, 0x9e, 0x60, 0xb8, 0xd2, 0x62, + 0x78, 0xe3, 0xa5, 0x31, 0x72, 0x1d, 0x26, 0x1d, 0x66, 0xc6, 0xef, 0x1c, + 0x04, 0x60, 0x08, 0x30, 0x40, 0x94, 0xd2, 0x1e, 0x4d, 0xac, 0xab, 0x0c, + 0x66, 0x96, 0xed, 0x19, 0x00, 0x3d, 0xe1, 0xbc, 0x7c, 0x35, 0x42, 0x79, + 0x49, 0x19, 0x21, 0x82, 0x42, 0x44, 0xc9, 0x74, 0x09, 0xba, 0x67, 0x8a, + 0x66, 0x56, 0xc8, 0x80, 0x5b, 0x48, 0x25, 0xca, 0x8f, 0x71, 0x04, 0xc3, + 0xc3, 0x13, 0x2b, 0x3a, 0x61, 0x99, 0x54, 0x20, 0x25, 0x11, 0xa5, 0x31, + 0x71, 0xc0, 0x6a, 0x64, 0xab, 0x36, 0x27, 0x69, 0x45, 0x2c, 0x31, 0xed, + 0xb2, 0x51, 0x24, 0x93, 0x0a, 0xca, 0x5b, 0x60, 0x61, 0x0c, 0x32, 0xdc, + 0xc4, 0x96, 0x71, 0x09, 0x53, 0x0a, 0x48, 0xa0, 0xb3, 0x15, 0x28, 0x0b, + 0x25, 0x28, 0x88, 0xb1, 0xc5, 0x92, 0x16, 0x59, 0x02, 0x56, 0x48, 0x34, + 0x8b, 0x16, 0x61, 0xc4, 0x11, 0xc5, 0x69, 0x1b, 0x52, 0x72, 0x41, 0x22, + 0x1b, 0x66, 0xc8, 0xa2, 0x29, 0x23, 0xcb, 0x02, 0x4e, 0xa3, 0x0d, 0x22, + 0x24, 0xef, 0x08, 0x90, 0xcc, 0xe9, 0xe4, 0xb7, 0x08, 0x89, 0x89, 0x22, + 0x5d, 0x51, 0x85, 0x46, 0x7b, 0x65, 0x54, 0x21, 0x03, 0x12, 0x66, 0x52, + 0x12, 0x30, 0x82, 0x09, 0x5a, 0xa2, 0xc9, 0x89, 0xc8, 0xc3, 0x3f, 0x0a, + 0x1e, 0xc9, 0x95, 0x4d, 0xe9, 0x3b, 0xdc, 0x48, 0x91, 0x65, 0x45, 0xa2, + 0x2a, 0x65, 0x9a, 0x6d, 0x21, 0x04, 0xa2, 0x9d, 0x72, 0x28, 0x87, 0x48, + 0xcc, 0xa3, 0x6c, 0xc4, 0xb7, 0x5e, 0x48, 0xf7, 0xcc, 0xe3, 0x52, 0xb0, + 0x50, 0xda, 0x33, 0x18, 0x2e, 0x24, 0xc6, 0xb3, 0xca, 0xde, 0x06, 0x06, + 0xeb, 0xb9, 0x18, 0x98, 0x8c, 0x4e, 0x6b, 0x36, 0xd9, 0x94, 0xcc, 0x33, + 0x05, 0x04, 0xcb, 0xdc, 0xfb, 0x1b, 0xee, 0x38, 0xd0, 0x04, 0x48, 0x82, + 0xed, 0xc3, 0x28, 0xb3, 0x49, 0xe6, 0xe2, 0x71, 0x4b, 0x29, 0x57, 0xc3, + 0x44, 0x07, 0x72, 0xd7, 0xcb, 0xd6, 0x30, 0x01, 0x30, 0x4e, 0x8d, 0x25, + 0x07, 0x61, 0x30, 0x84, 0x67, 0xb8, 0x79, 0x20, 0x25, 0x8b, 0xde, 0x8e, + 0xe7, 0xd5, 0xfa, 0xac, 0x72, 0x72, 0x09, 0x15, 0x3f, 0xd5, 0xb3, 0x6c, + 0xcd, 0x93, 0xef, 0x10, 0x30, 0xeb, 0x29, 0xf5, 0x18, 0xa5, 0x93, 0xe6, + 0x74, 0xe1, 0x73, 0x71, 0x6b, 0x10, 0xd5, 0xbf, 0xda, 0xc1, 0xa9, 0x94, + 0x25, 0x14, 0x88, 0x58, 0xf0, 0x67, 0x30, 0x41, 0xf3, 0x29, 0xae, 0x31, + 0x83, 0x50, 0x8c, 0xf4, 0xcb, 0x19, 0xf9, 0x1c, 0x9e, 0x39, 0x08, 0x8c, + 0x99, 0x33, 0x7f, 0x5d, 0x54, 0xfe, 0xb0, 0x27, 0x09, 0xcd, 0xcc, 0x46, + 0x49, 0x73, 0xe4, 0xd5, 0x5d, 0xc5, 0x47, 0x04, 0x61, 0x27, 0xcc, 0x31, + 0x6c, 0xd4, 0xde, 0x92, 0xbc, 0x71, 0xb6, 0x73, 0x9f, 0xfa, 0x68, 0xf7, + 0x82, 0x7e, 0x38, 0x48, 0x56, 0x75, 0x7a, 0x88, 0x6e, 0x27, 0x04, 0xce, + 0x99, 0xe1, 0x37, 0xa9, 0x2e, 0xef, 0xd4, 0x5c, 0xcc, 0x5c, 0x7c, 0x17, + 0xc9, 0x5a, 0x9a, 0xa7, 0x5b, 0xc0, 0x11, 0xbf, 0xdf, 0xb7, 0x82, 0xc9, + 0xed, 0xd7, 0xce, 0x7b, 0xcb, 0xe2, 0xfc, 0x2a, 0x4a, 0x5b, 0x1b, 0x16, + 0xa6, 0x96, 0x2a, 0x0b, 0x7b, 0xce, 0x2c, 0x46, 0x4c, 0x76, 0xd2, 0xf6, + 0x31, 0x04, 0xe6, 0x58, 0x88, 0xf3, 0x88, 0x6e, 0x3a, 0xb9, 0xae, 0xbd, + 0x9a, 0xcf, 0xa8, 0x0e, 0x67, 0x48, 0x1e, 0x0a, 0xc5, 0xb0, 0xde, 0x7a, + 0x6b, 0x5c, 0x59, 0xd1, 0x75, 0x38, 0x88, 0xaf, 0x5a, 0xc4, 0x5b, 0x81, + 0x95, 0x98, 0x92, 0x2c, 0x2b, 0x20, 0x79, 0x96, 0xae, 0xa1, 0xbc, 0xff, + 0x00, 0x9b, 0x3c, 0xbd, 0x95, 0x08, 0x63, 0xcb, 0xf7, 0x11, 0xae, 0x22, + 0x4c, 0xcc, 0x00, 0xac, 0xa4, 0x68, 0x09, 0x87, 0xd5, 0x82, 0xa0, 0x70, + 0x42, 0x46, 0x91, 0x16, 0x7a, 0x5c, 0xab, 0x18, 0x44, 0xd8, 0x46, 0xe3, + 0x96, 0x24, 0x00, 0x83, 0x4f, 0x41, 0x24, 0xac, 0x18, 0xa0, 0x98, 0x49, + 0xc8, 0x3c, 0x9f, 0x09, 0x65, 0x11, 0x55, 0x33, 0x57, 0x98, 0xbc, 0x38, + 0x75, 0xc7, 0x08, 0xa4, 0x0a, 0x45, 0x2c, 0x8c, 0x98, 0xac, 0x4f, 0xe9, + 0xc2, 0xc9, 0x6e, 0x51, 0x4a, 0x14, 0x6f, 0xbc, 0xa5, 0x74, 0xcc, 0x67, + 0x90, 0xd3, 0x00, 0x09, 0x9d, 0x22, 0x08, 0xa5, 0x25, 0x90, 0xcc, 0xd2, + 0xe4, 0x86, 0x4b, 0x6b, 0x06, 0x84, 0xe5, 0x73, 0x09, 0x94, 0x9b, 0x99, + 0xb3, 0x8d, 0xc1, 0x39, 0x65, 0x00, 0x9b, 0xad, 0x85, 0x85, 0x22, 0x0b, + 0x66, 0x46, 0x53, 0x94, 0x0b, 0x41, 0xac, 0x04, 0xc1, 0x33, 0x56, 0x66, + 0x12, 0xbf, 0x1c, 0x92, 0x18, 0x14, 0x8a, 0x23, 0x00, 0x69, 0x27, 0xb0, + 0x2c, 0x02, 0x0e, 0x29, 0x49, 0x96, 0x50, 0x84, 0x02, 0x4c, 0x0a, 0xf0, + 0x35, 0x1d, 0xcd, 0xcf, 0x1b, 0x4a, 0x90, 0x1e, 0x40, 0xb1, 0x44, 0xcd, + 0x4c, 0x66, 0x14, 0x18, 0x54, 0x2c, 0x81, 0x25, 0x81, 0x13, 0x4c, 0x0c, + 0x28, 0x18, 0x26, 0x26, 0xdb, 0xbd, 0x65, 0x90, 0xb9, 0x81, 0x58, 0x67, + 0xa4, 0xd2, 0x4f, 0x3e, 0x59, 0x8e, 0x60, 0x30, 0x91, 0x86, 0x00, 0xd2, + 0xdc, 0x3b, 0x20, 0x6a, 0x63, 0x1c, 0x38, 0xd6, 0x0c, 0x35, 0x76, 0x60, + 0x63, 0x31, 0x73, 0x0a, 0x77, 0xc4, 0x63, 0x3b, 0x5c, 0x90, 0xa2, 0x23, + 0x6c, 0xe0, 0x30, 0x9a, 0xbe, 0x33, 0x0a, 0x41, 0x6c, 0x8c, 0xba, 0xc2, + 0x66, 0x3a, 0x5f, 0x30, 0xbc, 0x70, 0x8a, 0x34, 0x1c, 0xbb, 0x60, 0xa5, + 0x4e, 0xfc, 0xc4, 0xca, 0xc6, 0xc0, 0xe1, 0xb7, 0xe0, 0x23, 0xb0, 0xb2, + 0x65, 0x4f, 0x0f, 0x2a, 0x23, 0x2c, 0xc4, 0x30, 0x27, 0x8d, 0xa1, 0xa7, + 0xbc, 0xd0, 0xf1, 0xd0, 0xfb, 0xad, 0x93, 0x68, 0xd6, 0xbf, 0x5c, 0x1c, + 0x11, 0x06, 0x09, 0x8b, 0xdd, 0x38, 0xea, 0xe7, 0xc6, 0x79, 0x89, 0xc2, + 0x71, 0x47, 0x77, 0xf7, 0x73, 0x3a, 0xc1, 0x1c, 0x64, 0x42, 0x20, 0x10, + 0xc4, 0xfc, 0x4b, 0xf3, 0x06, 0xa8, 0x99, 0x2a, 0x94, 0x88, 0x7c, 0xee, + 0xfe, 0xe1, 0xde, 0x9a, 0x66, 0xf8, 0xbb, 0x4c, 0x24, 0xca, 0x4e, 0x5c, + 0x4f, 0x55, 0x0d, 0x63, 0x21, 0x1c, 0x50, 0x53, 0x5b, 0x62, 0xe3, 0x3e, + 0xf3, 0x31, 0xae, 0x2b, 0x02, 0x90, 0xa4, 0x5a, 0x2b, 0x3e, 0x98, 0xb3, + 0x55, 0x76, 0x71, 0x18, 0x4a, 0x7a, 0x33, 0x0d, 0x2d, 0xcd, 0xb2, 0x8c, + 0xc6, 0xa7, 0x92, 0xc0, 0xe2, 0x99, 0xc4, 0x3e, 0x7f, 0x56, 0x71, 0x4d, + 0x63, 0x83, 0x37, 0x11, 0x38, 0xdf, 0x99, 0x82, 0x8f, 0xec, 0xe3, 0x93, + 0xb1, 0x4b, 0x19, 0x7a, 0xfd, 0x7e, 0x7d, 0xf0, 0x99, 0x99, 0x88, 0x58, + 0xbc, 0x41, 0x05, 0x06, 0x3a, 0x11, 0xaf, 0xc0, 0x4c, 0xe5, 0xf5, 0xeb, + 0x38, 0x84, 0xf9, 0xb6, 0x87, 0x8e, 0x62, 0x6a, 0x55, 0xf3, 0xe4, 0xc1, + 0xf8, 0xbd, 0x71, 0x86, 0x2b, 0x1f, 0x9c, 0xf8, 0xf3, 0xee, 0xa7, 0x84, + 0x13, 0x33, 0xb4, 0x88, 0xce, 0x8f, 0x38, 0xfe, 0x31, 0xcb, 0x9c, 0x55, + 0xe0, 0x5b, 0xa8, 0xbf, 0xd0, 0x77, 0xb6, 0x79, 0x09, 0x25, 0xaf, 0xde, + 0x71, 0x3f, 0xd0, 0x26, 0xcc, 0x72, 0x24, 0x64, 0x0d, 0x40, 0xa9, 0x39, + 0x4a, 0x3f, 0x05, 0x6a, 0x78, 0xa7, 0xfe, 0x9c, 0x1f, 0x2d, 0xd4, 0xe9, + 0xfa, 0xff, 0x00, 0x3d, 0x16, 0x11, 0x9c, 0x44, 0x7e, 0xb2, 0x87, 0xec, + 0xf4, 0xe4, 0x3a, 0xb4, 0xe6, 0xb7, 0xd1, 0xf7, 0x5e, 0xb8, 0xca, 0xa7, + 0x6c, 0x45, 0xa1, 0x81, 0x66, 0xa4, 0x83, 0xa2, 0x30, 0xbc, 0x2c, 0x04, + 0x49, 0x1c, 0x25, 0x79, 0x06, 0x60, 0x54, 0x18, 0xc3, 0x13, 0x6d, 0x84, + 0xec, 0x66, 0x8b, 0x52, 0x48, 0x92, 0x16, 0x20, 0x82, 0xc5, 0x98, 0x63, + 0x92, 0x25, 0x2a, 0x14, 0x3c, 0x25, 0x8b, 0x92, 0x91, 0x55, 0x10, 0xe4, + 0x88, 0x46, 0x18, 0x62, 0xa4, 0x61, 0x84, 0x87, 0x24, 0xc5, 0xae, 0x61, + 0xd9, 0x44, 0xb4, 0x88, 0x40, 0x8a, 0x40, 0x43, 0xec, 0xa1, 0x13, 0xa4, + 0x55, 0x88, 0xe2, 0x94, 0x81, 0x6a, 0x41, 0x2d, 0x44, 0x8b, 0xc1, 0x21, + 0x13, 0x71, 0x2b, 0xc5, 0xb0, 0x50, 0x80, 0x93, 0x05, 0xa4, 0xa2, 0x4b, + 0x4d, 0xcc, 0xb2, 0x11, 0x80, 0x8c, 0x26, 0xa8, 0x32, 0x95, 0x19, 0x94, + 0xe6, 0xe6, 0x70, 0x04, 0x67, 0x91, 0x61, 0x4b, 0x6d, 0x84, 0x9e, 0xc6, + 0x11, 0x7a, 0xf5, 0x47, 0xbd, 0x00, 0x4a, 0x34, 0x8c, 0x37, 0x1c, 0x4a, + 0xc2, 0xba, 0x85, 0xe2, 0xf2, 0xcd, 0x00, 0x62, 0x18, 0x46, 0x82, 0x64, + 0x41, 0x6d, 0xf0, 0x81, 0x25, 0xf3, 0x6b, 0x8d, 0x52, 0x89, 0xa0, 0x65, + 0xb7, 0x5c, 0x4a, 0x16, 0x53, 0x39, 0x36, 0x96, 0xcb, 0x24, 0x45, 0x52, + 0x4a, 0x4d, 0x72, 0xc9, 0x23, 0x7a, 0xc2, 0x60, 0x08, 0xe0, 0xa6, 0x55, + 0x5b, 0x9b, 0x60, 0xca, 0xc5, 0x58, 0xb2, 0x67, 0xd3, 0x2e, 0xfb, 0x32, + 0xad, 0x2b, 0x16, 0x9b, 0x28, 0x22, 0x75, 0x99, 0x97, 0xe6, 0x93, 0x8a, + 0x4a, 0xe4, 0x60, 0x86, 0xbb, 0x0f, 0xdf, 0x17, 0x71, 0x9e, 0x00, 0x15, + 0xac, 0xc1, 0x4c, 0x9d, 0x8b, 0x11, 0x51, 0xfb, 0xa0, 0xb9, 0x30, 0x22, + 0xc2, 0x39, 0x63, 0x3e, 0x1e, 0x20, 0x63, 0x0e, 0x78, 0x38, 0x31, 0x2d, + 0x6e, 0x46, 0x58, 0x9a, 0x4d, 0x33, 0xf4, 0x54, 0x54, 0x19, 0x01, 0xd8, + 0x9a, 0x3a, 0xc6, 0xb4, 0x4f, 0x26, 0x50, 0x76, 0xab, 0xe7, 0x07, 0xc7, + 0xe6, 0x79, 0x17, 0x81, 0xa9, 0x62, 0x3e, 0x75, 0x30, 0x9b, 0xef, 0x90, + 0x54, 0xc2, 0x65, 0xe0, 0x23, 0xa6, 0x55, 0xd4, 0x9f, 0xbb, 0x0c, 0x00, + 0x7b, 0x3e, 0xe1, 0xcc, 0x6a, 0x66, 0xee, 0xb3, 0xc2, 0x0d, 0x2e, 0xda, + 0xb3, 0x5a, 0xfd, 0xef, 0x15, 0xcd, 0x2f, 0x8c, 0xbd, 0xee, 0x3c, 0x39, + 0xac, 0xf7, 0x6f, 0x20, 0x64, 0x11, 0xb7, 0x56, 0x9a, 0x6e, 0xf5, 0x1e, + 0x23, 0x81, 0x99, 0x40, 0x97, 0x77, 0xc2, 0xa8, 0xaf, 0x1a, 0x78, 0x49, + 0x28, 0x88, 0xeb, 0xaf, 0x4b, 0xfe, 0xf8, 0xe7, 0xe8, 0xc2, 0xef, 0x05, + 0x75, 0xcc, 0xcd, 0xe3, 0x9f, 0xd9, 0xe4, 0xcf, 0x39, 0xac, 0xfe, 0xd1, + 0x01, 0x97, 0x5a, 0xfc, 0x59, 0xc2, 0x10, 0xac, 0x57, 0xf6, 0xf8, 0xe7, + 0x5e, 0x58, 0x16, 0x46, 0xf7, 0x90, 0x4c, 0x49, 0x15, 0x13, 0x92, 0x2e, + 0x5b, 0x39, 0x3a, 0x72, 0xe4, 0x31, 0xdc, 0x55, 0x6b, 0x1c, 0x59, 0x51, + 0x89, 0x86, 0xa9, 0xf6, 0xce, 0x3e, 0x2f, 0xd7, 0x05, 0x48, 0x02, 0x72, + 0xfa, 0xc1, 0x0c, 0x6b, 0xc4, 0x4b, 0xc9, 0x22, 0xcf, 0x10, 0xc1, 0x2d, + 0x58, 0x39, 0x3e, 0x78, 0xc4, 0x02, 0xf5, 0xbe, 0x28, 0xf6, 0xf6, 0xc0, + 0xa7, 0x1c, 0xb5, 0xbb, 0x26, 0x7f, 0x3e, 0x9b, 0xfa, 0xff, 0x00, 0x36, + 0x9d, 0x3f, 0x7b, 0x89, 0x9a, 0x82, 0xa2, 0x7c, 0x9d, 0x71, 0x09, 0xad, + 0x80, 0xbb, 0x9c, 0x19, 0x04, 0x85, 0x57, 0x0a, 0xd8, 0x4f, 0x23, 0xa9, + 0x01, 0x91, 0x82, 0xcc, 0x24, 0x82, 0xb1, 0x2e, 0x48, 0x84, 0x9e, 0x4b, + 0x09, 0x0a, 0xb2, 0x6f, 0x35, 0x13, 0xd0, 0xcd, 0x24, 0xd2, 0xa6, 0x38, + 0xe4, 0x0d, 0xaa, 0xb9, 0x07, 0x4f, 0xca, 0xe1, 0x68, 0xb3, 0xcb, 0x24, + 0x28, 0x29, 0x80, 0x49, 0x26, 0x58, 0x4a, 0x88, 0x3d, 0x12, 0xc8, 0x5b, + 0xc4, 0x28, 0x49, 0x15, 0x92, 0x08, 0x43, 0x45, 0x4a, 0xa4, 0x04, 0xc8, + 0xb3, 0x40, 0x5f, 0xfb, 0xcb, 0x40, 0x08, 0x12, 0xd3, 0x7d, 0x5e, 0xe0, + 0x7b, 0xdc, 0xe4, 0xcf, 0x96, 0x26, 0x3d, 0xb1, 0x99, 0x72, 0xcb, 0x50, + 0x90, 0x84, 0xb8, 0x39, 0x4b, 0x22, 0xca, 0x8a, 0x44, 0x0d, 0xc6, 0x0b, + 0xb8, 0x81, 0xa6, 0x23, 0x8d, 0x34, 0xad, 0xdd, 0xd3, 0x89, 0xc4, 0x04, + 0x6c, 0x6b, 0xf4, 0xe2, 0xc8, 0x12, 0xc3, 0x28, 0xcb, 0x06, 0xf5, 0xd3, + 0x77, 0x8b, 0xba, 0xe4, 0xde, 0x31, 0x9b, 0x24, 0x96, 0x6e, 0x40, 0x81, + 0xae, 0xf7, 0x21, 0x2c, 0x8e, 0x6e, 0x62, 0x31, 0x17, 0xfd, 0x4a, 0x20, + 0xdb, 0xa3, 0xfc, 0xdc, 0x55, 0x3d, 0x39, 0xfd, 0xe0, 0x25, 0xfb, 0xef, + 0x84, 0x2d, 0x01, 0x79, 0x21, 0x29, 0x0d, 0x4c, 0xdc, 0xa5, 0x85, 0x11, + 0x41, 0x1c, 0x04, 0x05, 0x9c, 0x88, 0x0b, 0x22, 0x58, 0x58, 0x54, 0x11, + 0x86, 0x56, 0xa1, 0x95, 0x82, 0x52, 0x29, 0xb0, 0xde, 0x45, 0xa8, 0x5b, + 0xf2, 0xc1, 0x7c, 0x94, 0x25, 0x50, 0x82, 0x05, 0x46, 0xc9, 0x91, 0x25, + 0x67, 0xb1, 0x98, 0xd3, 0x50, 0x61, 0x00, 0x80, 0xb7, 0x30, 0x93, 0x4e, + 0x10, 0x12, 0xe5, 0xb2, 0x26, 0x86, 0x00, 0x00, 0x4b, 0x36, 0x33, 0x51, + 0x5e, 0xf6, 0x11, 0x74, 0x42, 0xff, 0x00, 0xbf, 0x38, 0xcc, 0xf9, 0xf3, + 0x9b, 0xe9, 0x9d, 0xa4, 0x4a, 0x93, 0x68, 0x54, 0x06, 0x7d, 0xe2, 0xd9, + 0x9a, 0x34, 0x43, 0x7d, 0x21, 0xbe, 0x22, 0xaa, 0xda, 0x78, 0x24, 0xae, + 0x8c, 0x79, 0xfc, 0xf2, 0x26, 0x01, 0x0c, 0x67, 0xfb, 0x73, 0xf7, 0x75, + 0x87, 0x82, 0x12, 0x45, 0x64, 0x9c, 0x63, 0xe6, 0xa4, 0x71, 0x37, 0x89, + 0xe2, 0xee, 0x6c, 0x48, 0x98, 0x44, 0xf9, 0xf9, 0xd4, 0xeb, 0x8c, 0x87, + 0x73, 0x45, 0xe3, 0xba, 0x6f, 0x26, 0xa7, 0x73, 0x7f, 0xe6, 0x44, 0xba, + 0x46, 0x1b, 0x88, 0x0a, 0xf7, 0x8d, 0xba, 0x88, 0x5e, 0x4c, 0x13, 0x41, + 0x94, 0xd3, 0x98, 0xa2, 0x88, 0x6e, 0xf9, 0x31, 0x20, 0x2c, 0x15, 0xa8, + 0x99, 0x86, 0x54, 0xb8, 0xc2, 0xc4, 0x86, 0x45, 0xe1, 0x12, 0xc0, 0xa1, + 0x1b, 0x64, 0xa2, 0xe7, 0x1a, 0x9b, 0xbc, 0x02, 0x4f, 0x26, 0xb6, 0xc1, + 0x98, 0xb8, 0x87, 0xbe, 0x99, 0x5c, 0x85, 0x92, 0x48, 0xe3, 0x06, 0x04, + 0x00, 0x23, 0x62, 0x8c, 0xad, 0x19, 0x93, 0x6d, 0x54, 0x04, 0x03, 0x28, + 0x62, 0x44, 0x95, 0x43, 0x28, 0x83, 0xb3, 0x55, 0x50, 0xcb, 0xfe, 0xfa, + 0x42, 0x89, 0x84, 0x5e, 0x07, 0x6c, 0x98, 0x8c, 0x5b, 0x36, 0x33, 0x1c, + 0x9d, 0xac, 0xe5, 0x18, 0x7d, 0x96, 0x1a, 0x88, 0x9a, 0xaf, 0x1c, 0x18, + 0xce, 0xb1, 0x52, 0xfb, 0xfe, 0x26, 0x52, 0x68, 0xea, 0x93, 0xda, 0x11, + 0x9a, 0x9d, 0xcd, 0xbf, 0x66, 0x6a, 0x35, 0xc7, 0xcc, 0x4a, 0x78, 0x20, + 0x0a, 0xa3, 0xba, 0xc9, 0xfa, 0xc8, 0xd1, 0x46, 0x06, 0xe9, 0x24, 0x26, + 0x89, 0x0a, 0xde, 0x7b, 0x18, 0x8a, 0x3d, 0xce, 0x3d, 0x16, 0x9d, 0x12, + 0xa2, 0x07, 0x4f, 0xf9, 0xc8, 0x49, 0x7d, 0x80, 0x20, 0x9f, 0x76, 0xdf, + 0x83, 0xc7, 0x2e, 0x18, 0x63, 0xb6, 0x98, 0x95, 0xf2, 0xb2, 0xd7, 0xe6, + 0xce, 0x18, 0x23, 0x2b, 0x17, 0x60, 0x95, 0x11, 0xf6, 0x26, 0x55, 0x99, + 0xa8, 0x46, 0x51, 0x0c, 0x85, 0x12, 0xa2, 0x0d, 0x95, 0x60, 0xc8, 0x97, + 0x51, 0x21, 0xcc, 0x09, 0x2c, 0xc0, 0x89, 0xa5, 0x8b, 0x4a, 0x3b, 0x58, + 0x2a, 0xc9, 0x98, 0xe2, 0x86, 0x1b, 0x41, 0x35, 0x1b, 0x19, 0x80, 0xb6, + 0x00, 0x78, 0xc3, 0xc9, 0x52, 0x86, 0x66, 0x00, 0xd0, 0xe7, 0xd0, 0xa8, + 0xc4, 0xc8, 0xcf, 0xfb, 0xec, 0xdc, 0x27, 0x64, 0x74, 0xbd, 0xe2, 0x88, + 0x9d, 0xeb, 0x30, 0xf1, 0x00, 0x4c, 0xb6, 0x01, 0x83, 0x53, 0xf8, 0xef, + 0x1a, 0x38, 0x35, 0x21, 0x33, 0x8b, 0xc1, 0xe2, 0xce, 0xbf, 0x49, 0x26, + 0x5e, 0x39, 0x8b, 0x64, 0xbe, 0xaf, 0xf7, 0xf5, 0xfa, 0x73, 0x15, 0x2b, + 0xa9, 0xb6, 0x77, 0x7f, 0xbc, 0xd0, 0xf2, 0x22, 0xb0, 0x18, 0xdd, 0x90, + 0xe8, 0xb3, 0x98, 0xcc, 0xed, 0x9f, 0x3c, 0x55, 0x44, 0x32, 0xfe, 0x1c, + 0xf7, 0x8f, 0xe9, 0xfe, 0x6a, 0x28, 0xcd, 0xd3, 0x18, 0x6f, 0x75, 0x33, + 0xb9, 0xc4, 0x72, 0xf7, 0xa0, 0xd8, 0x26, 0x94, 0x8b, 0x37, 0x29, 0x0b, + 0x1f, 0x14, 0xa3, 0x69, 0x4a, 0x09, 0x9b, 0x0c, 0x46, 0x08, 0xa9, 0x09, + 0x80, 0x9f, 0x3c, 0x81, 0x89, 0x53, 0x25, 0xa8, 0xb5, 0x26, 0x5b, 0xcc, + 0x05, 0x7e, 0xe2, 0x24, 0x81, 0xc1, 0x03, 0x0c, 0x24, 0x42, 0xb1, 0x40, + 0x00, 0x13, 0xb8, 0x93, 0xc4, 0x33, 0x0b, 0x2f, 0x94, 0x98, 0x8c, 0x52, + 0x2e, 0x58, 0x6a, 0x5b, 0x80, 0xc8, 0xac, 0xa0, 0x41, 0x84, 0x11, 0xf2, + 0x64, 0x27, 0x67, 0x87, 0xfb, 0xc2, 0xb6, 0xe2, 0x28, 0x4c, 0xef, 0xba, + 0x99, 0xb9, 0x75, 0xd4, 0x37, 0x01, 0x1e, 0xd7, 0x12, 0x44, 0xf9, 0xcc, + 0x4c, 0xe5, 0x37, 0xcb, 0x26, 0x0b, 0x99, 0x04, 0x80, 0x1c, 0x93, 0xfa, + 0xea, 0x71, 0x3c, 0x21, 0x94, 0x4a, 0xf3, 0x8f, 0x5b, 0xb8, 0xf3, 0x7c, + 0xf3, 0x74, 0x38, 0xdc, 0xeb, 0x1d, 0x6b, 0xf3, 0x68, 0xb9, 0x9e, 0xfb, + 0x12, 0x50, 0xf1, 0x78, 0x0d, 0x7b, 0x6c, 0x8e, 0x48, 0x51, 0xb7, 0xc5, + 0x57, 0xe3, 0x24, 0x1b, 0x87, 0xaa, 0xff, 0x00, 0x2a, 0x24, 0xd7, 0x7e, + 0xcd, 0x3e, 0x67, 0xad, 0x1e, 0x39, 0x24, 0x4c, 0xcc, 0x4d, 0x7c, 0xf2, + 0x6a, 0xc9, 0xaa, 0x9d, 0x70, 0x4c, 0x61, 0x4e, 0x82, 0xc1, 0x18, 0x44, + 0x66, 0x7e, 0x72, 0x57, 0x16, 0x34, 0x83, 0x52, 0x86, 0x22, 0xb5, 0x53, + 0xf0, 0x4c, 0x59, 0x32, 0x21, 0xf7, 0x5d, 0xc8, 0x96, 0xa2, 0xf7, 0x83, + 0x5a, 0xf0, 0xf0, 0x81, 0xa6, 0x36, 0x28, 0x18, 0x53, 0xa5, 0x10, 0x94, + 0x94, 0x80, 0xbc, 0x53, 0x63, 0x1a, 0x94, 0xa8, 0x30, 0x9e, 0xd9, 0x86, + 0x32, 0x48, 0x84, 0xff, 0x00, 0x79, 0x42, 0xa6, 0xd3, 0xb8, 0x7c, 0x66, + 0x28, 0xef, 0xeb, 0x42, 0x52, 0x51, 0x5a, 0xf2, 0x51, 0x11, 0x6c, 0x47, + 0xfc, 0x98, 0xe2, 0x08, 0xcb, 0x59, 0x8f, 0xb8, 0xf9, 0xd6, 0xbe, 0x23, + 0x84, 0x2f, 0x6f, 0x68, 0x17, 0x50, 0x79, 0xfc, 0xf4, 0x54, 0xf0, 0xa9, + 0x0a, 0x87, 0xe6, 0xb4, 0x49, 0x07, 0x95, 0xdf, 0xbe, 0x3c, 0x14, 0x4a, + 0x5b, 0x92, 0xfa, 0xb1, 0x6c, 0x34, 0xcc, 0xc5, 0x3c, 0x44, 0x6c, 0x31, + 0x79, 0xaa, 0x7c, 0xe7, 0xa8, 0x9d, 0xff, 0x00, 0x9b, 0x8a, 0x3e, 0x72, + 0x3c, 0xf2, 0xf7, 0x1f, 0x6e, 0x78, 0x98, 0x62, 0x6c, 0x44, 0x80, 0x06, + 0x18, 0xbc, 0xe0, 0xbc, 0x34, 0xdc, 0x8a, 0x26, 0x08, 0x49, 0xb9, 0x59, + 0xd8, 0x25, 0x90, 0x90, 0x20, 0xe6, 0x9b, 0xe6, 0x02, 0x3c, 0x26, 0xd4, + 0xc4, 0x48, 0x1e, 0xc0, 0x36, 0xcb, 0x5c, 0x07, 0x0d, 0x91, 0x2d, 0x0d, + 0x66, 0x44, 0x41, 0xa0, 0x86, 0xc2, 0x9e, 0x42, 0x8d, 0xc2, 0x42, 0x4a, + 0x24, 0x89, 0x4b, 0x95, 0x99, 0x27, 0x17, 0x67, 0x0b, 0x40, 0x48, 0xe8, + 0x67, 0x01, 0x2f, 0x43, 0x26, 0x26, 0x2d, 0xa2, 0x7f, 0xdf, 0xc4, 0x49, + 0x26, 0x5c, 0x56, 0x20, 0xbc, 0xf9, 0xb9, 0xe6, 0x21, 0x29, 0x6c, 0xee, + 0x2b, 0x6c, 0x4c, 0x5c, 0x4f, 0x8a, 0x5c, 0x42, 0x95, 0x0e, 0x61, 0x8d, + 0xde, 0x3f, 0x5d, 0x57, 0xbe, 0x4c, 0xb8, 0x6a, 0x6e, 0xbf, 0x48, 0x7b, + 0x8c, 0x7a, 0xae, 0x29, 0x6f, 0x42, 0xf3, 0x8c, 0xb8, 0x8d, 0xb5, 0x31, + 0xf0, 0xf0, 0x9b, 0x22, 0xda, 0xb0, 0xad, 0x61, 0x09, 0x89, 0x8f, 0xcb, + 0x93, 0x18, 0x89, 0xaf, 0x31, 0x01, 0x98, 0xb9, 0x11, 0xef, 0xe6, 0x7f, + 0xcd, 0x81, 0xdc, 0xb5, 0xea, 0x3c, 0x95, 0x2b, 0xd8, 0xd1, 0xc1, 0x2b, + 0x54, 0xca, 0xe2, 0xd5, 0x88, 0x34, 0xb2, 0x56, 0x58, 0x23, 0x94, 0x42, + 0xb2, 0xd4, 0xcb, 0x70, 0x18, 0x26, 0x31, 0x38, 0x22, 0xda, 0xb7, 0x8d, + 0xaa, 0x60, 0x22, 0x65, 0x6f, 0x5b, 0x0f, 0x4d, 0x91, 0x1e, 0x46, 0x16, + 0x51, 0x52, 0xdb, 0x11, 0x52, 0x27, 0x74, 0x04, 0x55, 0xbb, 0xe2, 0x8d, + 0xcd, 0x44, 0x1b, 0xd8, 0x24, 0x91, 0x13, 0x27, 0x89, 0x1f, 0x80, 0x9d, + 0x19, 0xb5, 0x2a, 0x48, 0x69, 0x2d, 0x2d, 0x35, 0x10, 0x6a, 0x4f, 0xf7, + 0xa4, 0x72, 0x59, 0x34, 0xcb, 0x96, 0xc9, 0x4c, 0x4b, 0xa2, 0x65, 0x7a, + 0x89, 0x46, 0x18, 0x3e, 0x6a, 0x42, 0x0d, 0xdf, 0x91, 0x66, 0x17, 0x98, + 0x21, 0xaa, 0x91, 0x8b, 0xd6, 0x63, 0x1f, 0x2e, 0xbc, 0x1c, 0x0b, 0x97, + 0x22, 0xc0, 0xc5, 0x6a, 0x72, 0x63, 0x3d, 0x75, 0xc8, 0x61, 0x27, 0xbb, + 0x3e, 0x75, 0x9c, 0x6b, 0x7c, 0x08, 0x42, 0xe0, 0x17, 0x0c, 0xf6, 0xd0, + 0x33, 0xa2, 0x6c, 0x87, 0x92, 0x5f, 0x02, 0xb1, 0xd2, 0xb9, 0x17, 0xd6, + 0xf7, 0xfe, 0x6d, 0x3a, 0x67, 0x8c, 0x15, 0x95, 0x8f, 0x3b, 0xa3, 0x39, + 0x4e, 0x2d, 0x00, 0x74, 0x4a, 0x21, 0x03, 0x50, 0x48, 0xf8, 0xd8, 0x41, + 0xc6, 0x04, 0x81, 0x90, 0x0d, 0x2c, 0x30, 0x4c, 0xc4, 0x4d, 0x60, 0x8a, + 0x85, 0x57, 0x88, 0x46, 0x42, 0x56, 0x48, 0x24, 0x80, 0xcb, 0x52, 0x88, + 0xb8, 0x88, 0xcc, 0xe5, 0x0c, 0xaa, 0x29, 0x20, 0x85, 0x08, 0x84, 0x6c, + 0xd2, 0x31, 0x31, 0x89, 0xe0, 0xb6, 0x42, 0xd8, 0xdc, 0x24, 0xa8, 0x6e, + 0x4c, 0x90, 0x62, 0x0a, 0xa2, 0x11, 0x62, 0x08, 0x4c, 0xa0, 0x96, 0x13, + 0xa2, 0x48, 0x40, 0x8c, 0x61, 0xc0, 0xff, 0x00, 0xbe, 0x92, 0x6c, 0xc1, + 0x8c, 0x31, 0xfa, 0x75, 0x57, 0x34, 0xed, 0xb1, 0x50, 0xda, 0x2e, 0x30, + 0x16, 0x5f, 0x71, 0x2e, 0x72, 0x0d, 0x90, 0x36, 0xd1, 0x10, 0x98, 0xf5, + 0x73, 0xe6, 0x9d, 0x10, 0xf1, 0x58, 0x67, 0xcc, 0xcc, 0x55, 0x77, 0x3f, + 0x4c, 0xc4, 0x5f, 0x0a, 0x75, 0x73, 0xf2, 0x64, 0x4b, 0xeb, 0xd6, 0xc6, + 0x2b, 0x8a, 0x69, 0x24, 0xa4, 0x44, 0x9d, 0x47, 0xe2, 0x2f, 0xb2, 0x63, + 0x8a, 0x89, 0x9b, 0x7c, 0xea, 0xf3, 0xb6, 0x75, 0x3d, 0xd7, 0xf9, 0xc3, + 0xcf, 0x37, 0x43, 0xe7, 0xfe, 0xc4, 0xcf, 0x7c, 0x40, 0xaa, 0x2d, 0x51, + 0x93, 0x44, 0x90, 0x8a, 0x88, 0x44, 0x69, 0xc4, 0x9e, 0x29, 0x0c, 0x89, + 0x10, 0x1c, 0xe1, 0x16, 0x03, 0x04, 0xe2, 0x96, 0x50, 0xb3, 0xc2, 0x50, + 0x12, 0x61, 0x15, 0x7b, 0xa1, 0xa9, 0x11, 0xc8, 0x32, 0xd8, 0x70, 0x44, + 0x20, 0x1c, 0xa8, 0x10, 0xa4, 0x22, 0x33, 0x86, 0xf1, 0x76, 0x4b, 0xe2, + 0x8b, 0x21, 0x22, 0x32, 0x8a, 0xae, 0xdd, 0xa1, 0x1a, 0x99, 0xf2, 0xbc, + 0x32, 0x61, 0x12, 0x8c, 0x91, 0x00, 0x18, 0x68, 0x58, 0x10, 0x65, 0xd0, + 0x9f, 0xef, 0xd4, 0x32, 0x4a, 0x15, 0x33, 0xbf, 0xda, 0x73, 0x53, 0x19, + 0x66, 0xaa, 0x13, 0x0a, 0xfc, 0x54, 0xb3, 0x6b, 0x0d, 0xd2, 0xfc, 0x40, + 0xcf, 0x08, 0x49, 0x25, 0x7c, 0x93, 0x39, 0x98, 0xb8, 0x24, 0x9a, 0x86, + 0xa6, 0x6d, 0x99, 0xe9, 0xee, 0x18, 0x01, 0x22, 0x20, 0x3c, 0x33, 0xd6, + 0xb3, 0x1c, 0x25, 0x71, 0xd0, 0x66, 0xd9, 0x83, 0xbf, 0x3f, 0x89, 0xe6, + 0x40, 0xcc, 0x38, 0x90, 0x3e, 0x6b, 0xc9, 0x65, 0x7c, 0x10, 0xe5, 0xb2, + 0x64, 0x88, 0xce, 0x98, 0x93, 0x1d, 0xeb, 0x1f, 0xe6, 0xd2, 0x26, 0x3e, + 0xbb, 0x3b, 0xd6, 0x8b, 0xd6, 0x78, 0x48, 0xb8, 0x4e, 0x42, 0x50, 0xd7, + 0xd3, 0x2c, 0xcd, 0xf8, 0x4c, 0xf1, 0x88, 0x2a, 0xa3, 0x03, 0x00, 0xda, + 0x13, 0x40, 0x6d, 0x34, 0x04, 0x13, 0x00, 0x70, 0x0c, 0x86, 0x15, 0x94, + 0x98, 0x10, 0xd5, 0x44, 0x05, 0x6a, 0x00, 0xcc, 0x9c, 0x1d, 0xa6, 0xc4, + 0x03, 0x2c, 0x8b, 0x34, 0x49, 0xb5, 0x99, 0x98, 0x58, 0x78, 0x2e, 0x11, + 0x29, 0x22, 0x65, 0x02, 0x2d, 0x57, 0x6c, 0x62, 0x15, 0x59, 0x0b, 0x78, + 0x08, 0x09, 0x04, 0xdc, 0x28, 0x09, 0x74, 0x13, 0x28, 0x85, 0xb7, 0x70, + 0x23, 0x47, 0xfb, 0xd0, 0x66, 0x22, 0xef, 0xdf, 0xe6, 0x3c, 0x4e, 0x65, + 0xbe, 0x0a, 0x02, 0x5a, 0x99, 0x8c, 0x11, 0xb7, 0xec, 0xee, 0x66, 0x2c, + 0xe5, 0x43, 0x2c, 0x79, 0x37, 0x25, 0xff, 0x00, 0x1f, 0x78, 0x87, 0x04, + 0x41, 0xc8, 0x99, 0xc1, 0x9d, 0xfe, 0xd5, 0xdf, 0x0f, 0x7a, 0xc3, 0x3f, + 0xcb, 0xf0, 0x9d, 0x48, 0xeb, 0x8f, 0x1d, 0x9e, 0x82, 0x04, 0xb4, 0x04, + 0xcb, 0x84, 0x19, 0xb5, 0x62, 0x30, 0xb9, 0xf3, 0xb6, 0x7a, 0x9f, 0xe2, + 0xc8, 0xba, 0xf3, 0xfe, 0x71, 0x44, 0x2a, 0x3c, 0x4f, 0xa6, 0xbd, 0xef, + 0xc7, 0x53, 0xca, 0xa8, 0x66, 0x5b, 0x02, 0x79, 0x9b, 0x08, 0x87, 0x59, + 0xd3, 0x6a, 0x01, 0x83, 0x31, 0x04, 0x40, 0x10, 0x9c, 0x03, 0x14, 0x5c, + 0xe0, 0xcd, 0x2c, 0x44, 0x4c, 0x24, 0x98, 0x25, 0x5b, 0x64, 0xb5, 0x24, + 0x56, 0x22, 0x58, 0x75, 0xc8, 0x2b, 0x15, 0x62, 0xe5, 0x12, 0x44, 0xe1, + 0xc8, 0x32, 0x9e, 0xf8, 0xa1, 0x52, 0x4c, 0x4c, 0x16, 0x84, 0x94, 0xd1, + 0x49, 0x77, 0x95, 0x96, 0x5e, 0x10, 0x50, 0x89, 0x8c, 0x0c, 0xcb, 0x28, + 0x20, 0x4b, 0x69, 0xbe, 0x86, 0x3f, 0xdf, 0x10, 0x2b, 0x48, 0x45, 0x3f, + 0xf9, 0xf0, 0x7f, 0x3c, 0x49, 0x21, 0x4c, 0x09, 0xa6, 0x2a, 0xc7, 0x71, + 0xff, 0x00, 0xb0, 0x3c, 0x42, 0xa4, 0x17, 0x2e, 0x63, 0x1f, 0x86, 0x34, + 0xd4, 0xdb, 0xc9, 0xa0, 0x75, 0x37, 0x46, 0xc4, 0x47, 0xe6, 0xa9, 0xcc, + 0xd5, 0xf0, 0x33, 0x4a, 0x1a, 0x72, 0x31, 0xdc, 0x49, 0xfa, 0xef, 0x90, + 0x45, 0x61, 0x8c, 0xa0, 0x21, 0x46, 0x46, 0x24, 0x67, 0xd3, 0x04, 0x76, + 0xe4, 0x5c, 0xf5, 0xd9, 0xf9, 0xf9, 0xf1, 0xfe, 0x6e, 0x24, 0xc2, 0x5f, + 0xaf, 0xf8, 0x20, 0xf6, 0x93, 0x89, 0x68, 0xe4, 0x20, 0xaa, 0x89, 0x90, + 0x4d, 0x1c, 0xc3, 0x61, 0x6c, 0xcc, 0x8b, 0x6b, 0x45, 0x06, 0x51, 0x56, + 0xd8, 0xe5, 0x8c, 0xfa, 0x22, 0xb8, 0x34, 0x4a, 0x96, 0x1c, 0x23, 0xa1, + 0x76, 0x21, 0x70, 0xdb, 0x0f, 0x20, 0x91, 0x01, 0x99, 0x40, 0xab, 0x3a, + 0x43, 0xbb, 0x95, 0xa9, 0x05, 0x94, 0x89, 0x41, 0x48, 0x22, 0x07, 0x2a, + 0x33, 0x7e, 0x22, 0x62, 0x5f, 0x5c, 0x9c, 0xcd, 0x54, 0x23, 0xb1, 0xd0, + 0x22, 0x44, 0x94, 0x8c, 0x0d, 0xe7, 0xfd, 0xff, 0x00, 0x7a, 0x37, 0x88, + 0x7d, 0x17, 0x9f, 0x4c, 0xcf, 0x2e, 0x06, 0x22, 0x15, 0x5c, 0x84, 0x11, + 0xdf, 0xd1, 0x17, 0x58, 0xe4, 0x52, 0x3b, 0xb6, 0xeb, 0x38, 0x96, 0x2b, + 0x15, 0x54, 0x96, 0xf1, 0x9b, 0x04, 0x21, 0x5e, 0xb5, 0xaf, 0xd8, 0x86, + 0xc9, 0x87, 0x49, 0x48, 0x7a, 0x9e, 0xf3, 0x43, 0xf1, 0x23, 0x12, 0x52, + 0xea, 0x44, 0x6e, 0x26, 0x99, 0x4b, 0x28, 0x96, 0x76, 0x55, 0x8d, 0x8d, + 0xcf, 0x23, 0x46, 0xdc, 0x3a, 0xf4, 0x51, 0x3d, 0x78, 0xf7, 0xfe, 0x68, + 0x3e, 0x92, 0x7c, 0x78, 0xf9, 0x76, 0x78, 0x94, 0xa5, 0xb0, 0x0d, 0xc1, + 0x5f, 0x99, 0x2c, 0x8f, 0x24, 0x4b, 0x04, 0x1c, 0x1a, 0x22, 0x14, 0x04, + 0x90, 0x11, 0x2d, 0x30, 0x81, 0x04, 0xc4, 0xa3, 0x8c, 0x9c, 0x99, 0x82, + 0x8b, 0xc9, 0x35, 0xf6, 0xe0, 0xef, 0x25, 0xe7, 0x72, 0x2a, 0x2a, 0x31, + 0x54, 0xc5, 0x6c, 0xce, 0x64, 0xbc, 0x86, 0x40, 0x0a, 0x88, 0x85, 0x9c, + 0x05, 0x0c, 0x2c, 0x8a, 0x31, 0xe2, 0x08, 0xea, 0x79, 0x90, 0x09, 0x13, + 0x19, 0x4a, 0x32, 0x80, 0x22, 0x75, 0xdc, 0x20, 0x8f, 0xfb, 0xe2, 0x80, + 0x91, 0x45, 0xb9, 0xbf, 0xe3, 0x6f, 0x9f, 0x8e, 0x00, 0x90, 0x86, 0x4a, + 0x71, 0x11, 0x57, 0x31, 0x3f, 0x2f, 0x78, 0x63, 0x93, 0x6c, 0x07, 0x3b, + 0xaa, 0xbb, 0xdc, 0xef, 0xbc, 0xdf, 0x20, 0xc8, 0xa8, 0x16, 0xc9, 0x5d, + 0xfc, 0x4f, 0x57, 0xe3, 0x86, 0x41, 0x3a, 0x4b, 0x2b, 0x1d, 0xce, 0xbb, + 0x3e, 0x36, 0xcc, 0x1b, 0x9a, 0x08, 0xae, 0x42, 0x57, 0x05, 0x90, 0xda, + 0x53, 0xe6, 0x38, 0x85, 0xc5, 0xfa, 0xc7, 0x67, 0x5f, 0xc5, 0xc6, 0xff, + 0x00, 0xce, 0xa9, 0x31, 0xaa, 0x26, 0x61, 0x7c, 0xc6, 0x7a, 0xfd, 0xce, + 0x48, 0x34, 0xce, 0x53, 0x0c, 0x6c, 0x07, 0xb1, 0x82, 0x15, 0x35, 0xc0, + 0x9d, 0x28, 0xe9, 0x96, 0x62, 0x02, 0x40, 0x96, 0x56, 0x95, 0x59, 0x55, + 0xe0, 0x90, 0xa8, 0x88, 0xc8, 0x44, 0xb3, 0x34, 0xc9, 0xd8, 0x2c, 0x54, + 0x0f, 0x99, 0x28, 0x30, 0x6c, 0x11, 0x65, 0xc4, 0x60, 0xd3, 0x72, 0xb5, + 0x28, 0xc7, 0x05, 0x10, 0x26, 0x09, 0x02, 0x70, 0x4a, 0xd1, 0x85, 0x06, + 0x59, 0x65, 0x07, 0x10, 0xa8, 0x90, 0xd3, 0x6b, 0x01, 0x80, 0x34, 0x41, + 0x86, 0xbe, 0x4c, 0x2b, 0x5f, 0xef, 0x01, 0x1a, 0x97, 0x02, 0xd7, 0xcc, + 0xc7, 0x98, 0xcc, 0xe2, 0xe3, 0x8c, 0x54, 0xd6, 0x9b, 0xdd, 0x19, 0x51, + 0xf8, 0x8d, 0x0f, 0x3b, 0xc3, 0x6f, 0x74, 0x95, 0x99, 0xa8, 0xad, 0xfc, + 0x46, 0x40, 0x06, 0x9a, 0x1a, 0x4f, 0x36, 0x1d, 0x93, 0xdb, 0x81, 0x8a, + 0xe4, 0x61, 0x46, 0x31, 0x6f, 0xc6, 0x7f, 0x15, 0x3f, 0x7c, 0x99, 0x4e, + 0x2c, 0x22, 0x26, 0x74, 0x8d, 0x8c, 0x7e, 0x6f, 0x1c, 0x74, 0x45, 0xa9, + 0xf5, 0xf8, 0xae, 0x95, 0xec, 0xf5, 0xfe, 0x50, 0x78, 0x57, 0x7f, 0x51, + 0xf3, 0xf6, 0xcf, 0x05, 0x46, 0x02, 0xe8, 0x21, 0x9a, 0xa0, 0x0b, 0x42, + 0xd3, 0x24, 0xdc, 0xcf, 0x1a, 0xc3, 0xa8, 0x73, 0x3e, 0x99, 0x0a, 0xd3, + 0xfa, 0x31, 0xc8, 0x3e, 0x62, 0x5f, 0x10, 0x8b, 0x89, 0xea, 0x75, 0x9d, + 0xec, 0x92, 0xa5, 0xed, 0xa2, 0x92, 0xca, 0x90, 0xe0, 0x17, 0x94, 0xe8, + 0xe5, 0x07, 0xeb, 0x85, 0x87, 0x3d, 0xf5, 0x25, 0xef, 0xe1, 0x28, 0x17, + 0x36, 0x30, 0x49, 0xb8, 0x27, 0x63, 0x92, 0x0b, 0xa6, 0x27, 0xfd, 0xf1, + 0x40, 0x52, 0x37, 0xb5, 0x66, 0xd9, 0x97, 0xc1, 0xd5, 0xea, 0x38, 0x84, + 0x04, 0x12, 0x5b, 0x4f, 0x81, 0xb9, 0xc6, 0x66, 0x67, 0xd7, 0x19, 0x61, + 0x8b, 0x6d, 0xee, 0x8f, 0x3d, 0x5a, 0xbc, 0x8c, 0x09, 0x80, 0x47, 0x31, + 0x33, 0xeb, 0xe3, 0xf5, 0xe1, 0x2a, 0x73, 0x1f, 0x2f, 0xd4, 0x46, 0x33, + 0xe2, 0x73, 0xc5, 0x59, 0x31, 0x43, 0x82, 0x45, 0x93, 0x13, 0x64, 0xb0, + 0x60, 0xae, 0x49, 0x9a, 0x26, 0xf1, 0xd3, 0xdd, 0x5f, 0xbb, 0x7c, 0xff, + 0x00, 0x9a, 0x07, 0x39, 0x21, 0x3b, 0x85, 0xfd, 0x4b, 0xe8, 0x73, 0xcd, + 0x4f, 0x49, 0x23, 0x05, 0x25, 0x2c, 0x6f, 0xdb, 0x2e, 0x20, 0x24, 0x92, + 0xf5, 0x01, 0xa6, 0x69, 0x94, 0x67, 0x12, 0xce, 0x30, 0xe2, 0x38, 0x29, + 0x29, 0x09, 0x19, 0x51, 0xc5, 0x32, 0xb7, 0x1a, 0x08, 0xb7, 0x9a, 0x67, + 0x8f, 0xb5, 0x68, 0xcc, 0xcd, 0xb5, 0xdc, 0x3a, 0xff, 0x00, 0xce, 0x49, + 0xd5, 0xe0, 0x8c, 0x6e, 0x64, 0x7f, 0x0b, 0x09, 0x2f, 0x83, 0x8e, 0x26, + 0x1b, 0xdb, 0xd9, 0x98, 0xf9, 0x8b, 0xf8, 0x67, 0xfd, 0xfa, 0x0b, 0xa9, + 0xee, 0x09, 0xd9, 0xb2, 0x3f, 0xb9, 0xc0, 0x21, 0x61, 0x25, 0xee, 0xfb, + 0xd4, 0x5a, 0x39, 0x97, 0xbe, 0x38, 0x01, 0x36, 0xee, 0xff, 0x00, 0x0e, + 0x0c, 0x4e, 0xd7, 0xb7, 0x82, 0x65, 0x04, 0x47, 0x9a, 0x29, 0xcf, 0xc5, + 0x1f, 0xa7, 0x24, 0x94, 0x48, 0x33, 0x12, 0x79, 0xef, 0xf8, 0xfc, 0xf2, + 0x62, 0x88, 0x1e, 0xfa, 0xcd, 0xde, 0x8d, 0x45, 0x69, 0x38, 0xc4, 0x77, + 0x2b, 0xd6, 0xb3, 0xd9, 0x19, 0xf3, 0xf3, 0xfe, 0x6a, 0x3a, 0x31, 0xfc, + 0xf7, 0xd9, 0xa8, 0xe9, 0x78, 0xdf, 0x86, 0xb0, 0xf7, 0x13, 0x31, 0x55, + 0x51, 0x73, 0xdf, 0x18, 0x16, 0x4e, 0x8b, 0xa6, 0xa0, 0x64, 0x5e, 0x86, + 0x49, 0xed, 0x8d, 0x70, 0x09, 0x71, 0x8c, 0x45, 0x37, 0x53, 0xf1, 0x39, + 0xa6, 0x23, 0x9b, 0x33, 0x17, 0x81, 0x86, 0xcc, 0xd5, 0xd4, 0x17, 0xdc, + 0x73, 0x37, 0x80, 0x37, 0xe0, 0xc4, 0x01, 0xd1, 0x2e, 0xa4, 0x98, 0x89, + 0x61, 0x00, 0x55, 0x29, 0x9d, 0x13, 0x11, 0x37, 0x7b, 0xa9, 0xbc, 0xa1, + 0xfe, 0xfa, 0x02, 0x72, 0x19, 0x70, 0xfa, 0xf3, 0x8e, 0xdb, 0x8e, 0x60, + 0x71, 0x58, 0xd1, 0x31, 0xa2, 0x72, 0x4c, 0x77, 0x08, 0xc6, 0x39, 0x0c, + 0x13, 0x75, 0x1e, 0x4a, 0xf8, 0x96, 0xe2, 0x74, 0xc7, 0xb3, 0x4b, 0x33, + 0xe8, 0x8f, 0xcb, 0x32, 0x6e, 0x7c, 0xcc, 0xea, 0x3d, 0xc0, 0xea, 0x23, + 0x10, 0x6a, 0x0f, 0xbc, 0x6e, 0x5e, 0x1b, 0x26, 0xc5, 0x75, 0x04, 0xfb, + 0x24, 0xc8, 0xd4, 0xe3, 0x73, 0xc5, 0x4b, 0x33, 0x2e, 0x20, 0x98, 0x1a, + 0x96, 0xe8, 0xdf, 0x71, 0x23, 0x3f, 0xe7, 0x01, 0x66, 0x1b, 0x7b, 0x09, + 0x9c, 0x47, 0xe4, 0xf3, 0x27, 0x23, 0x9e, 0xcc, 0xd2, 0x94, 0x1e, 0x63, + 0x0c, 0xbf, 0x82, 0xb9, 0xf0, 0xc0, 0xc3, 0x64, 0xfd, 0x84, 0x05, 0x30, + 0xc3, 0x06, 0x57, 0x94, 0xc6, 0x91, 0xfb, 0xc9, 0x3f, 0x13, 0x18, 0x0d, + 0xf9, 0x48, 0x87, 0x3e, 0x30, 0xcd, 0x66, 0x4f, 0xc1, 0x17, 0x8a, 0xe2, + 0xe0, 0x33, 0x65, 0xe2, 0x69, 0x11, 0xe6, 0x5c, 0x56, 0xb3, 0x9b, 0x6d, + 0x9d, 0x66, 0xf3, 0xd7, 0xc8, 0xc4, 0x56, 0x49, 0xef, 0xfd, 0xe8, 0xc2, + 0x33, 0x03, 0x59, 0x3a, 0xbc, 0x79, 0x83, 0xc9, 0x31, 0x3c, 0xc0, 0x6d, + 0x96, 0x6c, 0x8a, 0x00, 0xab, 0x5e, 0xf3, 0xb9, 0xbe, 0x1d, 0x58, 0xc6, + 0x84, 0xce, 0x71, 0x33, 0xef, 0x04, 0xcc, 0x4f, 0x1d, 0x43, 0x0c, 0xf8, + 0xa8, 0x8b, 0xc6, 0xcf, 0x17, 0xf3, 0x65, 0xb7, 0x45, 0xba, 0xdc, 0x62, + 0x63, 0xc6, 0x5d, 0x31, 0x5c, 0x04, 0x99, 0x90, 0x1a, 0x23, 0x30, 0x85, + 0xcd, 0xc5, 0xc5, 0x45, 0x92, 0xe1, 0x26, 0x6f, 0x32, 0x66, 0x9b, 0xd4, + 0x98, 0xf1, 0x79, 0xd7, 0xf9, 0x64, 0x7b, 0x1b, 0x90, 0xdb, 0x12, 0xc5, + 0xd4, 0x19, 0x93, 0x67, 0x18, 0x59, 0xd2, 0x35, 0x2c, 0x34, 0xe6, 0x26, + 0x5b, 0x3e, 0xf6, 0xa1, 0x64, 0xde, 0xd8, 0xea, 0xed, 0x8a, 0x52, 0x34, + 0x26, 0xc5, 0xb4, 0x1d, 0x43, 0x8f, 0xd6, 0xb3, 0x7b, 0x59, 0xac, 0x52, + 0x1c, 0xf1, 0x37, 0x72, 0x90, 0x67, 0x15, 0x9a, 0xc4, 0xcb, 0x83, 0x5c, + 0x2e, 0xa6, 0xe0, 0x2a, 0xaf, 0x1d, 0xd4, 0xb3, 0xea, 0x2a, 0x2f, 0x86, + 0xc4, 0x9a, 0x23, 0x71, 0x0a, 0xfb, 0xd4, 0xf4, 0xdc, 0xb5, 0x7f, 0xef, + 0x4d, 0x25, 0x8e, 0x92, 0x3d, 0x9e, 0xfe, 0x1a, 0xea, 0xb8, 0x96, 0x22, + 0x13, 0x28, 0xc3, 0x1f, 0xbc, 0xbb, 0x6f, 0x1b, 0xe0, 0x2c, 0x65, 0x5a, + 0x57, 0xc7, 0x56, 0x6e, 0xfb, 0xcc, 0x71, 0x10, 0xca, 0xfe, 0x33, 0xd6, + 0x16, 0x7f, 0xb3, 0x52, 0x63, 0x2d, 0x47, 0x72, 0x77, 0x51, 0xee, 0xb9, + 0x2c, 0x51, 0x9e, 0xac, 0x7d, 0x9e, 0x3c, 0x60, 0xcf, 0x26, 0x2b, 0xae, + 0xe8, 0x7f, 0x82, 0x50, 0x9f, 0x89, 0x3f, 0xce, 0x61, 0x53, 0x82, 0xae, + 0x3c, 0xbf, 0x75, 0xf7, 0x67, 0x13, 0x12, 0x52, 0xe6, 0x28, 0x88, 0x2b, + 0x66, 0x20, 0x8c, 0x66, 0x38, 0xb2, 0x4e, 0x66, 0x77, 0x04, 0xf9, 0x98, + 0xdb, 0x25, 0x4a, 0x9c, 0x1d, 0xfc, 0x1b, 0xdd, 0xd5, 0x64, 0xba, 0x92, + 0x0f, 0x01, 0xc9, 0x61, 0x9e, 0xb2, 0x4e, 0x6c, 0xa8, 0xba, 0xf7, 0xf5, + 0xca, 0x12, 0xe1, 0x88, 0xd4, 0xc0, 0x98, 0xac, 0xe6, 0x08, 0x85, 0xd5, + 0x70, 0xe9, 0xc4, 0x12, 0x16, 0xc5, 0xd7, 0x53, 0xe7, 0x0f, 0x46, 0x7f, + 0xdf, 0x72, 0x09, 0x5a, 0x08, 0x7c, 0xca, 0x46, 0x4c, 0xbf, 0xf5, 0xb3, + 0x8c, 0xc3, 0x81, 0x06, 0x3b, 0xf5, 0xd5, 0x7e, 0x30, 0x04, 0x9c, 0x44, + 0x63, 0xdf, 0x61, 0xbb, 0x89, 0xef, 0x7f, 0x01, 0x3c, 0x70, 0x08, 0x51, + 0xb5, 0x09, 0x3e, 0xc7, 0xa3, 0x3f, 0x0f, 0x26, 0x21, 0x70, 0x10, 0xdc, + 0x7c, 0x85, 0xfb, 0xf7, 0x67, 0x1a, 0xce, 0x19, 0x24, 0xd6, 0x02, 0xa6, + 0x27, 0x77, 0x67, 0xd4, 0xc7, 0x82, 0x48, 0xf3, 0x9b, 0xf3, 0xf1, 0x3f, + 0xe6, 0xe9, 0xc4, 0x24, 0xf5, 0x25, 0xfb, 0x3f, 0x9e, 0xf8, 0xa0, 0xd8, + 0x64, 0xd6, 0x73, 0x1e, 0xff, 0x00, 0x59, 0x97, 0x20, 0x70, 0x4c, 0x4c, + 0x4a, 0x8b, 0xa3, 0xb4, 0xfe, 0xce, 0x5d, 0xf0, 0xf6, 0xf4, 0x61, 0xd4, + 0xb1, 0x0a, 0xeb, 0x7d, 0x94, 0xc1, 0xc6, 0x20, 0x94, 0xe9, 0x2c, 0x86, + 0xba, 0x46, 0x76, 0xaa, 0x09, 0x4d, 0x0f, 0x45, 0xe2, 0x62, 0xba, 0x3c, + 0x84, 0x98, 0x30, 0x8f, 0xbe, 0x56, 0x09, 0x2e, 0x2d, 0x73, 0x33, 0x96, + 0x1e, 0xdd, 0x91, 0xd0, 0xff, 0x00, 0x7f, 0x51, 0x6d, 0x13, 0x4c, 0x4c, + 0xdf, 0x84, 0x8f, 0xbf, 0x50, 0xa2, 0x70, 0x05, 0x64, 0xbc, 0x36, 0x5f, + 0x79, 0x77, 0x8e, 0x30, 0x0c, 0xdf, 0xdf, 0x98, 0x6b, 0xba, 0x3b, 0x8a, + 0xe2, 0x98, 0x07, 0x96, 0xa2, 0xbe, 0xfc, 0x45, 0xe5, 0xe0, 0xa4, 0xc5, + 0xeb, 0xb6, 0x3f, 0x79, 0xf1, 0x11, 0x18, 0x64, 0x15, 0x0a, 0xce, 0x09, + 0xa1, 0x52, 0x89, 0xee, 0x97, 0xb8, 0x3c, 0x1f, 0x57, 0xe0, 0xfe, 0x5a, + 0xfa, 0xf5, 0xfe, 0x75, 0x79, 0xac, 0x73, 0x75, 0xae, 0x6c, 0x6b, 0xe9, + 0xd4, 0xf1, 0x8b, 0x84, 0x84, 0xf3, 0x05, 0x46, 0x56, 0x24, 0xfc, 0x4b, + 0x75, 0x6f, 0x25, 0x4c, 0xed, 0x26, 0x33, 0xa9, 0xf4, 0xf7, 0xd9, 0x04, + 0xcc, 0x70, 0xee, 0x1c, 0xc7, 0xb1, 0x6d, 0x20, 0xcf, 0xa7, 0x18, 0xc7, + 0x25, 0x86, 0xf7, 0x33, 0x25, 0xbd, 0x1e, 0x2b, 0x19, 0xb3, 0x02, 0xf1, + 0x70, 0x4c, 0x1e, 0xcd, 0x26, 0x10, 0x2e, 0x90, 0x2e, 0x7c, 0x9c, 0x58, + 0x99, 0xa1, 0xf3, 0x99, 0xa2, 0x3b, 0xaa, 0x9c, 0x69, 0x16, 0x27, 0xfd, + 0xe1, 0xcd, 0x10, 0x1d, 0x0b, 0x88, 0x63, 0x17, 0xbc, 0xf9, 0x79, 0x39, + 0x05, 0x4e, 0xbb, 0xac, 0x52, 0xc6, 0x4a, 0x86, 0x66, 0x3c, 0xf0, 0x58, + 0xc8, 0x66, 0xca, 0x0a, 0x14, 0xeb, 0xab, 0x87, 0x2f, 0xda, 0x2f, 0x42, + 0x22, 0x33, 0x08, 0xcd, 0xcf, 0x5d, 0xee, 0x6d, 0x23, 0x8d, 0x43, 0x31, + 0x11, 0xbf, 0xbf, 0x53, 0x65, 0x3f, 0x3c, 0x59, 0xa5, 0xe5, 0x92, 0x22, + 0xe7, 0xd9, 0x7a, 0x08, 0xae, 0x9e, 0x39, 0x84, 0xa9, 0x56, 0xb2, 0xc4, + 0x53, 0xe2, 0x91, 0xaf, 0xbf, 0xf2, 0x6c, 0x5a, 0x9f, 0xe5, 0xfd, 0x00, + 0xde, 0x35, 0x33, 0x1c, 0x79, 0xe0, 0x1a, 0x33, 0x86, 0xce, 0x31, 0xac, + 0x4f, 0xdb, 0x41, 0xd2, 0x67, 0x06, 0xe4, 0x28, 0x22, 0x22, 0x0c, 0x59, + 0xd3, 0xc9, 0xc2, 0x88, 0x98, 0x64, 0xd4, 0xcc, 0x84, 0xdd, 0xcc, 0x43, + 0x1e, 0x6d, 0xe5, 0xc4, 0x2c, 0xa8, 0x0f, 0xb8, 0x71, 0xe9, 0x2e, 0xd9, + 0xb3, 0x39, 0xa2, 0x16, 0x95, 0x99, 0x9d, 0x27, 0x96, 0xa3, 0xe3, 0x19, + 0x9b, 0xe6, 0x84, 0x65, 0x98, 0x1b, 0xbc, 0xa4, 0x33, 0x11, 0xbb, 0xbd, + 0x7f, 0xbf, 0x04, 0x04, 0xa6, 0x30, 0xc4, 0x44, 0xce, 0xdf, 0x10, 0x4e, + 0x27, 0xa7, 0x92, 0x7c, 0x21, 0x59, 0xdf, 0xdf, 0xb8, 0x2e, 0x5f, 0x8e, + 0x4b, 0x10, 0xe2, 0x07, 0xf8, 0x9b, 0x75, 0xdf, 0xb8, 0xe0, 0x94, 0xd2, + 0xa1, 0x2f, 0x68, 0x31, 0x5e, 0xde, 0xfc, 0xe0, 0x16, 0x23, 0x76, 0x7e, + 0xc8, 0xf7, 0x1e, 0x39, 0x3e, 0x28, 0x4d, 0x29, 0x82, 0x43, 0xb0, 0x60, + 0xf2, 0x50, 0x3c, 0x54, 0x1f, 0xaf, 0x61, 0x7e, 0x27, 0x1f, 0x9f, 0xf3, + 0x49, 0x0d, 0x23, 0x0b, 0x8d, 0xda, 0xd7, 0x8e, 0xfb, 0x07, 0x97, 0xbe, + 0x65, 0x7a, 0xb1, 0x06, 0x3a, 0x22, 0xba, 0xc9, 0xcd, 0x20, 0x60, 0xf3, + 0x03, 0xe2, 0x69, 0xc5, 0xbd, 0x47, 0x57, 0xc8, 0x23, 0x1e, 0x61, 0xcc, + 0xda, 0x39, 0x18, 0x86, 0x24, 0x71, 0xd3, 0x83, 0x49, 0x03, 0x52, 0x59, + 0x9f, 0x4e, 0xd8, 0xc7, 0x9b, 0x81, 0x82, 0x66, 0x26, 0x66, 0x68, 0x8a, + 0x69, 0xc1, 0x06, 0xea, 0x58, 0x9d, 0x36, 0x71, 0x85, 0x9e, 0xc2, 0x31, + 0x64, 0xe6, 0xeb, 0xf9, 0x09, 0x54, 0x3f, 0xef, 0x6d, 0x25, 0x0d, 0x0c, + 0x7f, 0x31, 0xab, 0xeb, 0x38, 0xe1, 0xa1, 0x0d, 0x1e, 0xe0, 0x20, 0xd1, + 0x31, 0xd3, 0x34, 0x78, 0x6c, 0xe5, 0x5e, 0x18, 0x27, 0x16, 0x7a, 0x07, + 0xe9, 0xf3, 0xe3, 0x93, 0x30, 0x24, 0x61, 0xae, 0xab, 0xe7, 0x11, 0x37, + 0x53, 0xa9, 0x38, 0xab, 0x0f, 0xb8, 0xf5, 0x88, 0x5c, 0x68, 0xf7, 0x2e, + 0x2b, 0x8c, 0x45, 0x72, 0x69, 0x5a, 0x49, 0x62, 0xa7, 0xba, 0xf9, 0xe3, + 0xa9, 0x99, 0xc8, 0x89, 0x06, 0x2e, 0xbf, 0x98, 0x9f, 0xf3, 0x69, 0x0f, + 0xaa, 0xfd, 0xce, 0xa2, 0xbb, 0xc9, 0x7a, 0xe2, 0x7a, 0xa5, 0xaa, 0x75, + 0x0c, 0x46, 0x2b, 0xa3, 0x1f, 0x32, 0xa8, 0x02, 0x47, 0x49, 0x2d, 0x59, + 0x59, 0x73, 0x05, 0xcd, 0xe4, 0x77, 0x1c, 0x4c, 0x1c, 0x5c, 0xb5, 0x40, + 0xe8, 0x27, 0xce, 0x37, 0x23, 0xc6, 0xdf, 0xa7, 0x41, 0x53, 0x64, 0xc7, + 0xaf, 0x9b, 0xa7, 0x9e, 0x12, 0x3d, 0xcc, 0xac, 0xfb, 0x21, 0x8b, 0xb1, + 0x8f, 0x07, 0x02, 0xed, 0x01, 0x70, 0x4a, 0xc7, 0xab, 0x18, 0x86, 0xc2, + 0x73, 0x23, 0x5f, 0xef, 0xcc, 0x06, 0xc0, 0x45, 0x01, 0x09, 0x69, 0x2d, + 0x93, 0x20, 0x4c, 0xf9, 0x87, 0x81, 0x45, 0x19, 0x20, 0x1f, 0x0f, 0xa1, + 0xbc, 0x99, 0x9c, 0xf5, 0xc0, 0x01, 0x28, 0x90, 0x31, 0x11, 0x75, 0x3d, + 0x67, 0x43, 0xee, 0xeb, 0x9a, 0xc3, 0x77, 0x9b, 0x3c, 0xc5, 0x24, 0xf1, + 0xf9, 0xb3, 0x94, 0x1c, 0xb1, 0xdd, 0x08, 0x66, 0x23, 0x3f, 0x53, 0x75, + 0x55, 0x2b, 0xc5, 0xbe, 0xf3, 0xd7, 0x89, 0xfd, 0x26, 0x29, 0xe2, 0x9c, + 0x1d, 0x7f, 0xde, 0x23, 0xc3, 0x13, 0x3d, 0x7f, 0x9b, 0x85, 0x98, 0x12, + 0xfe, 0x98, 0xd4, 0xbc, 0x48, 0x50, 0x84, 0xf1, 0x18, 0x4f, 0x2a, 0x36, + 0xa8, 0x75, 0x78, 0x39, 0x36, 0x17, 0x03, 0x8b, 0x56, 0x91, 0xb9, 0x12, + 0x65, 0x70, 0x63, 0x16, 0xf1, 0x8f, 0x13, 0x14, 0x81, 0xd4, 0x0b, 0xb9, + 0xf6, 0xe0, 0x88, 0xb7, 0x82, 0x92, 0x92, 0x57, 0xbd, 0x01, 0x10, 0xcc, + 0x5c, 0xc7, 0x66, 0x0a, 0x84, 0x99, 0x90, 0x35, 0x05, 0xb2, 0xfa, 0x4f, + 0x5d, 0x6a, 0x58, 0xe4, 0x94, 0xb0, 0x38, 0x74, 0x24, 0x5b, 0x02, 0x4d, + 0x54, 0xd4, 0x41, 0xa7, 0xfd, 0xf9, 0xc3, 0x73, 0x07, 0x2b, 0x0d, 0xae, + 0x55, 0x35, 0x29, 0xd1, 0x38, 0xe1, 0x01, 0x44, 0x98, 0x31, 0x32, 0x6e, + 0x26, 0x89, 0xe8, 0x20, 0x9a, 0xe4, 0xe1, 0x71, 0xd9, 0xe6, 0xa0, 0x7b, + 0x33, 0x0c, 0xc6, 0x7e, 0x54, 0x69, 0x70, 0x6a, 0x02, 0x2e, 0x5a, 0x8a, + 0xb2, 0x99, 0xde, 0x0e, 0x5b, 0x25, 0x96, 0x20, 0xc4, 0xb8, 0xc1, 0x24, + 0x5f, 0xdc, 0x72, 0x95, 0xb8, 0x95, 0x5d, 0x32, 0x4e, 0xc9, 0x88, 0x35, + 0x27, 0xd3, 0x22, 0x3d, 0x57, 0xad, 0xc8, 0x3b, 0xfe, 0xeb, 0xfc, 0xa0, + 0x8f, 0x39, 0xe3, 0x23, 0x01, 0xf6, 0x77, 0x53, 0x83, 0x75, 0x42, 0x42, + 0x45, 0x70, 0x56, 0x19, 0xd4, 0x16, 0xca, 0xf0, 0x36, 0xfe, 0x96, 0x29, + 0x72, 0xe5, 0x62, 0x33, 0x04, 0xdf, 0x7c, 0x86, 0xa4, 0xf4, 0xe2, 0x8c, + 0x86, 0xb3, 0x4d, 0xe1, 0x16, 0xcf, 0x26, 0x99, 0x86, 0x4a, 0x1b, 0x22, + 0x2e, 0xe9, 0x34, 0x7a, 0x73, 0x9c, 0xb1, 0x13, 0x51, 0xb2, 0x65, 0x47, + 0xea, 0x75, 0x9a, 0xf1, 0x21, 0x74, 0x60, 0xba, 0x4d, 0xe2, 0x0f, 0xb9, + 0x6e, 0x1a, 0x68, 0x9f, 0xf7, 0x8b, 0xa0, 0x07, 0x76, 0xc9, 0x65, 0x95, + 0xed, 0x21, 0xc4, 0xe5, 0x2c, 0xad, 0x28, 0x2b, 0x60, 0xdc, 0xe2, 0x42, + 0x52, 0x7f, 0x32, 0x5b, 0x95, 0x78, 0x19, 0x48, 0xa1, 0x4a, 0x94, 0xd4, + 0x27, 0xe3, 0x16, 0xee, 0x36, 0x40, 0xb1, 0x3b, 0xef, 0xc9, 0xac, 0x66, + 0x0e, 0x44, 0x8c, 0xc8, 0xea, 0xa9, 0xa9, 0x72, 0xdd, 0xc9, 0x8e, 0x49, + 0x30, 0xe8, 0x26, 0x08, 0x12, 0x58, 0xcb, 0x0f, 0xdf, 0x5c, 0xbf, 0xc0, + 0x3e, 0x3d, 0x5b, 0xf8, 0x8c, 0x47, 0x5f, 0xe4, 0x96, 0x81, 0x05, 0x86, + 0xd5, 0x01, 0xc4, 0x90, 0x6a, 0xec, 0xec, 0xe5, 0x1a, 0x81, 0x68, 0xde, + 0x88, 0x53, 0x36, 0x5d, 0x49, 0x1e, 0xf8, 0xab, 0x72, 0x47, 0x6e, 0xea, + 0x1c, 0xa9, 0xb4, 0x1d, 0x41, 0x4f, 0x16, 0x5b, 0x41, 0x01, 0x26, 0xae, + 0xdc, 0xf7, 0x26, 0x98, 0xc9, 0x6c, 0x53, 0x96, 0xaa, 0xda, 0xef, 0xc0, + 0x77, 0x8b, 0x8a, 0x4a, 0xb5, 0x9c, 0x40, 0xb3, 0x70, 0x4d, 0x4d, 0x11, + 0x79, 0xaa, 0x3c, 0xf4, 0xf1, 0xf9, 0xb0, 0xde, 0x6a, 0x18, 0x59, 0x95, + 0xa7, 0x04, 0xc4, 0x96, 0x7f, 0xbe, 0xe2, 0x42, 0x0c, 0x1f, 0x02, 0x42, + 0xb3, 0xe1, 0xfd, 0xeb, 0x64, 0x02, 0xc8, 0x63, 0xbc, 0xa6, 0x72, 0xa1, + 0x6e, 0x0c, 0xd1, 0x5c, 0x71, 0x25, 0x21, 0x02, 0x10, 0x39, 0x66, 0x32, + 0xce, 0xec, 0xc6, 0x3c, 0xed, 0x2b, 0x67, 0x56, 0xc4, 0x14, 0x6e, 0x4d, + 0x5e, 0xa7, 0x8c, 0xc4, 0xa3, 0x50, 0x42, 0x53, 0x31, 0xea, 0xe6, 0xe7, + 0x30, 0x2c, 0x53, 0xc0, 0x23, 0x2a, 0xc7, 0xd0, 0xc3, 0x19, 0xc2, 0x71, + 0x0e, 0x31, 0x22, 0x71, 0x9a, 0x35, 0x06, 0x34, 0x03, 0x28, 0x8c, 0xde, + 0x23, 0xfc, 0xeb, 0x48, 0x99, 0x62, 0x66, 0x28, 0xaf, 0x62, 0x7e, 0x1c, + 0xaa, 0x76, 0x42, 0x93, 0x13, 0xf9, 0x06, 0x57, 0x13, 0xd4, 0x70, 0xdc, + 0x97, 0x92, 0x67, 0xa8, 0xc9, 0x05, 0xcc, 0x4c, 0x1b, 0xc9, 0x13, 0xc6, + 0x4c, 0x24, 0x46, 0x24, 0x4a, 0x47, 0xc6, 0x2a, 0x6e, 0x66, 0x63, 0x14, + 0x8d, 0xd9, 0xeb, 0xde, 0x27, 0xd1, 0xad, 0xc8, 0x3b, 0x78, 0x39, 0xc4, + 0xcb, 0xf9, 0xa9, 0x35, 0x32, 0x2d, 0xcd, 0x48, 0xcd, 0x71, 0x82, 0xe9, + 0x8a, 0x92, 0xa0, 0x23, 0xf7, 0x84, 0x3a, 0x90, 0x1b, 0xe2, 0x0c, 0x30, + 0x73, 0xfd, 0xff, 0x00, 0x0c, 0xf3, 0xf3, 0xe3, 0xce, 0xf1, 0xf9, 0x11, + 0xe7, 0xf1, 0xbf, 0x98, 0xc6, 0xf8, 0x86, 0x7f, 0xe3, 0xe3, 0x46, 0x5d, + 0x5b, 0x98, 0xc7, 0xf7, 0x17, 0x8b, 0xe6, 0xcf, 0x0f, 0x9f, 0x15, 0x6e, + 0x47, 0xf5, 0xf9, 0xef, 0xfe, 0xba, 0xc3, 0x7c, 0xff, 0x00, 0xde, 0x7f, + 0xaf, 0xe1, 0xcf, 0xd3, 0x9e, 0xfc, 0x71, 0xfd, 0x1f, 0xd9, 0xfc, 0xd6, + 0x5f, 0xff, 0x00, 0x74, 0xf2, 0xb9, 0xc3, 0xbf, 0xff, 0x00, 0x26, 0x82, + 0x63, 0x68, 0xf7, 0x71, 0x64, 0x7f, 0xe2, 0x99, 0xf4, 0xa6, 0xf1, 0xff, + 0x00, 0xcb, 0xcf, 0x3c, 0xf3, 0xcf, 0x1c, 0xf3, 0xca, 0xe6, 0x51, 0xfd, + 0x23, 0x6f, 0x8e, 0x7e, 0xcf, 0xfb, 0x7f, 0x57, 0xd7, 0xff, 0x00, 0x9e, + 0x09, 0x8f, 0xc3, 0xef, 0xbf, 0x07, 0x83, 0x63, 0xbf, 0xc1, 0x9e, 0x4e, + 0x3d, 0x83, 0x1b, 0x3d, 0x93, 0x9a, 0x4f, 0x64, 0x5f, 0x23, 0x86, 0x24, + 0x73, 0x10, 0x92, 0x2e, 0xf2, 0xcf, 0x43, 0xa6, 0x78, 0x68, 0x8e, 0xb2, + 0x53, 0x24, 0x6e, 0x08, 0xb0, 0xd7, 0x71, 0x3c, 0x51, 0x19, 0x6e, 0x08, + 0x99, 0xc9, 0x88, 0x85, 0x93, 0x33, 0x23, 0xad, 0xf1, 0x64, 0xea, 0x1a, + 0x9d, 0xf5, 0x1e, 0x33, 0xc4, 0x73, 0x1c, 0xd4, 0x65, 0x60, 0xac, 0xcf, + 0xf2, 0x19, 0xe0, 0x1e, 0x2c, 0xee, 0x89, 0xc8, 0x69, 0x85, 0xfe, 0x53, + 0xfe, 0x74, 0x94, 0x7d, 0x19, 0xb3, 0xc3, 0xa5, 0x06, 0x6d, 0xee, 0xa8, + 0xb4, 0x18, 0x2c, 0xc2, 0x4c, 0xc3, 0x30, 0x24, 0xfe, 0xc6, 0x15, 0x3f, + 0x32, 0xa4, 0x55, 0xc5, 0xab, 0x16, 0xb0, 0xe4, 0xa8, 0x3b, 0x16, 0x4c, + 0xc2, 0xe2, 0x35, 0xb9, 0xce, 0xf6, 0x7c, 0xe6, 0x22, 0xe0, 0x9e, 0xcf, + 0x84, 0x1f, 0x54, 0x58, 0x17, 0xd7, 0x78, 0x6f, 0xf0, 0xda, 0x9c, 0x0f, + 0x78, 0xa6, 0x45, 0x5b, 0xbe, 0x2e, 0x47, 0xb0, 0xa2, 0xf1, 0xa9, 0x22, + 0x71, 0x70, 0x4c, 0x55, 0x40, 0x3e, 0xfa, 0x90, 0x8a, 0x30, 0xc4, 0x63, + 0x44, 0x39, 0xa9, 0xe8, 0xa8, 0x32, 0xb2, 0xd4, 0x30, 0xdb, 0x83, 0xbb, + 0x98, 0xc5, 0x79, 0xe5, 0xec, 0x14, 0xc4, 0x9d, 0xd4, 0xf6, 0xaa, 0xcd, + 0xd4, 0xe4, 0x54, 0x39, 0x48, 0x8b, 0x1d, 0x47, 0x99, 0x6f, 0x01, 0xd1, + 0x64, 0x33, 0x8b, 0xe1, 0x13, 0x50, 0x4f, 0x63, 0x7e, 0x32, 0xcd, 0x99, + 0xca, 0xfd, 0x72, 0x65, 0xb5, 0xf1, 0x2d, 0x13, 0x4b, 0xaf, 0xc4, 0x63, + 0xc7, 0x10, 0xd6, 0xa1, 0xc8, 0xdf, 0x44, 0xda, 0x35, 0x0c, 0x3e, 0x0b, + 0xe1, 0x28, 0xa9, 0x72, 0xc6, 0x37, 0x91, 0x1b, 0xa0, 0xc6, 0x62, 0x8a, + 0xe1, 0x7f, 0xf8, 0x20, 0xc3, 0x2c, 0x11, 0xab, 0x2b, 0xba, 0x5b, 0xe4, + 0xc1, 0x13, 0x86, 0x12, 0x15, 0xfa, 0xe7, 0xc7, 0xce, 0x64, 0x9a, 0x72, + 0xe0, 0x19, 0x62, 0xab, 0x1e, 0xa0, 0x27, 0xcc, 0x44, 0x47, 0x2b, 0x4b, + 0xb2, 0x24, 0x13, 0xc3, 0xac, 0x3d, 0x93, 0x3a, 0xe4, 0x82, 0xd0, 0xc4, + 0x85, 0x57, 0xfd, 0xf9, 0x5e, 0xee, 0x38, 0xfc, 0x4a, 0x57, 0x55, 0xfa, + 0x74, 0x18, 0xcc, 0x40, 0x72, 0x22, 0x32, 0x3f, 0xb3, 0x20, 0x97, 0x7b, + 0xb2, 0xb0, 0x77, 0xcb, 0x4d, 0xfb, 0xde, 0xe5, 0x8c, 0x0d, 0xce, 0x7c, + 0x9c, 0x7c, 0x62, 0x73, 0x68, 0x90, 0x56, 0x6a, 0x3e, 0x7c, 0xf1, 0x89, + 0xd6, 0x32, 0x54, 0xb6, 0xe2, 0x3f, 0xbe, 0x0e, 0x6a, 0xfe, 0x73, 0x9b, + 0xf8, 0xbb, 0xed, 0xcf, 0xc9, 0x42, 0x31, 0x70, 0xe6, 0x73, 0x87, 0x69, + 0xfc, 0x55, 0x54, 0xb0, 0xd1, 0x53, 0x25, 0x62, 0x66, 0x76, 0x91, 0xe7, + 0xce, 0x97, 0x9d, 0x7c, 0xff, 0x00, 0x7b, 0xfd, 0x7c, 0x47, 0x18, 0xfb, + 0x2c, 0xcc, 0xbb, 0xc5, 0xdd, 0xe1, 0x99, 0xf0, 0xf2, 0xfd, 0xf5, 0x3d, + 0xfc, 0x7f, 0x15, 0x3b, 0xc1, 0xef, 0xd7, 0x71, 0x4a, 0x67, 0xb1, 0x9b, + 0xf6, 0x5e, 0x65, 0x88, 0x9a, 0xba, 0xbf, 0x15, 0x9e, 0xee, 0x75, 0x7b, + 0x8e, 0x44, 0xcc, 0xab, 0xef, 0x3f, 0x88, 0xfe, 0x66, 0xfa, 0xe0, 0xc6, + 0x1f, 0xfd, 0xfc, 0xe3, 0xfb, 0x1c, 0x4a, 0x4e, 0xf2, 0x7c, 0x86, 0x5e, + 0x90, 0xc9, 0x11, 0x8c, 0x9c, 0x41, 0x8b, 0xbb, 0x20, 0x83, 0x39, 0xfa, + 0xbc, 0xe2, 0xe3, 0x90, 0x48, 0x91, 0x60, 0x46, 0x09, 0x63, 0xbc, 0xef, + 0x74, 0x3c, 0x4a, 0x15, 0x12, 0x58, 0x1a, 0x24, 0x26, 0xc8, 0xf3, 0x9a, + 0x6b, 0xc7, 0x22, 0x6d, 0x42, 0x12, 0x63, 0x2d, 0xc5, 0x5b, 0x99, 0x71, + 0xb1, 0xc7, 0x05, 0xc3, 0x44, 0x62, 0x6c, 0xf0, 0xe1, 0xdb, 0x3b, 0x9f, + 0x48, 0x85, 0xac, 0xa5, 0x93, 0x1e, 0xae, 0xa3, 0x2c, 0x83, 0x8a, 0x9a, + 0xe3, 0x48, 0x4a, 0x3a, 0xa1, 0x05, 0x88, 0x90, 0xa3, 0xd8, 0xcf, 0x2f, + 0x9a, 0xe8, 0xb1, 0x34, 0x62, 0xa4, 0x9c, 0x9c, 0xe3, 0x4f, 0xf9, 0x80, + 0x92, 0x63, 0x68, 0x92, 0x21, 0x02, 0x54, 0x39, 0x40, 0xca, 0x18, 0x11, + 0x0b, 0x42, 0x76, 0xb7, 0xab, 0x0b, 0xd7, 0x12, 0x96, 0x24, 0xef, 0xe0, + 0x30, 0x1e, 0x8b, 0x9a, 0xdc, 0x4d, 0xb5, 0x30, 0x28, 0x6e, 0x06, 0xe3, + 0xd1, 0x8d, 0xe7, 0xc9, 0x37, 0xc5, 0x88, 0x66, 0xa2, 0x0d, 0x94, 0xd6, + 0x1b, 0xa1, 0x1b, 0xea, 0x42, 0xf9, 0x7f, 0x29, 0x38, 0xf8, 0x9c, 0xd2, + 0x86, 0x09, 0xa1, 0xa6, 0x82, 0x6d, 0x0f, 0x4c, 0xcc, 0x23, 0x38, 0xdb, + 0xf0, 0xf9, 0xcd, 0xf0, 0x6d, 0xbe, 0xea, 0xd7, 0x71, 0xec, 0xb6, 0x6e, + 0xef, 0x3c, 0xb9, 0xb4, 0xbb, 0x9e, 0xfd, 0x3f, 0xbd, 0x1e, 0x62, 0x39, + 0x78, 0x9b, 0x69, 0x19, 0x91, 0xf5, 0x13, 0x2b, 0x3d, 0x97, 0x82, 0x59, + 0xb1, 0xf5, 0xe0, 0x9a, 0xf3, 0x19, 0x88, 0x8c, 0xe7, 0xef, 0xee, 0x66, + 0x82, 0xb3, 0x1b, 0x5d, 0xff, 0x00, 0xd9, 0xe4, 0xc0, 0xd4, 0x46, 0x66, + 0x37, 0x09, 0x91, 0x7d, 0x9e, 0x3e, 0x79, 0xd7, 0x76, 0x5d, 0x84, 0x6b, + 0xc4, 0x3e, 0x37, 0x9d, 0x70, 0xfa, 0xc2, 0x63, 0x27, 0xc9, 0x05, 0xcf, + 0xc7, 0x8e, 0x12, 0xbb, 0xaf, 0xb1, 0x27, 0xac, 0x77, 0xb8, 0xe4, 0xeb, + 0xf6, 0x98, 0xef, 0xf4, 0xfe, 0x12, 0x78, 0xef, 0xd5, 0x78, 0xdd, 0x49, + 0x30, 0xff, 0x00, 0x77, 0x38, 0xac, 0x49, 0x45, 0xd4, 0x61, 0x8a, 0x37, + 0xfd, 0xae, 0x18, 0x7a, 0xcb, 0xde, 0xe3, 0x3a, 0xbd, 0x77, 0xe0, 0xe1, + 0xef, 0xbf, 0x7e, 0xaa, 0x31, 0x70, 0x6f, 0x6f, 0x18, 0x2a, 0x66, 0x3f, + 0x83, 0xda, 0xcd, 0x42, 0xc5, 0x5e, 0xf9, 0xd9, 0x5f, 0xf4, 0xea, 0x3d, + 0xfa, 0xe0, 0x90, 0x23, 0xc2, 0xa6, 0xf3, 0x72, 0x45, 0x79, 0xf3, 0xf2, + 0xe7, 0x33, 0x15, 0xeb, 0x14, 0x78, 0xf9, 0xfd, 0x6b, 0xfb, 0xbd, 0x77, + 0xfd, 0xf1, 0xbe, 0x2c, 0x5e, 0x9d, 0x11, 0xde, 0x05, 0xc6, 0x7c, 0x66, + 0xc6, 0xb9, 0xdb, 0xd7, 0xf7, 0xdf, 0x15, 0x55, 0x8c, 0xdf, 0x8f, 0x82, + 0xbe, 0x49, 0x82, 0xa3, 0x34, 0xff, 0x00, 0x6f, 0xaf, 0xd0, 0xc1, 0xbf, + 0xae, 0x5e, 0x26, 0x3b, 0xc9, 0x31, 0x68, 0xdc, 0x64, 0x22, 0xa6, 0xdb, + 0xe6, 0xf2, 0x4e, 0x22, 0x6b, 0xe3, 0xce, 0xf1, 0x8f, 0x74, 0xf7, 0x74, + 0xe4, 0xca, 0x1a, 0xcc, 0x66, 0x48, 0xbd, 0xf7, 0x57, 0x99, 0xcc, 0x45, + 0x4c, 0x7d, 0x67, 0xee, 0xb3, 0x31, 0xc7, 0xc4, 0x58, 0x65, 0x9a, 0x90, + 0x6b, 0xcc, 0xfd, 0x44, 0xd5, 0xf2, 0x9b, 0x41, 0xe6, 0xce, 0xe2, 0xaa, + 0xd6, 0x4a, 0x1a, 0x9e, 0xf9, 0x15, 0x34, 0x16, 0x5e, 0x3c, 0x13, 0xf2, + 0xe7, 0x3c, 0x98, 0x99, 0x91, 0xaa, 0xb5, 0x86, 0x5e, 0x85, 0xc5, 0x4d, + 0xc3, 0xe7, 0x80, 0xd4, 0xb3, 0x64, 0x18, 0x8e, 0xfd, 0xbb, 0xee, 0x7c, + 0xbc, 0x8e, 0xa7, 0x52, 0xe2, 0x34, 0x7c, 0x47, 0x92, 0x0b, 0x71, 0xc7, + 0x1c, 0xc4, 0x46, 0x5a, 0x32, 0x9a, 0x92, 0xd7, 0x09, 0xf3, 0x52, 0x0a, + 0x60, 0xc2, 0x23, 0xca, 0xef, 0xbf, 0xfd, 0xe7, 0x4d, 0x25, 0xf2, 0x58, + 0xd0, 0x88, 0x8a, 0x20, 0x38, 0xe4, 0x74, 0x94, 0xa8, 0x81, 0x55, 0xa6, + 0x40, 0x18, 0x84, 0xe4, 0xff, 0x00, 0x35, 0x59, 0x07, 0x87, 0x6e, 0xa0, + 0x1c, 0x90, 0x5a, 0xc6, 0x21, 0x33, 0x06, 0xc4, 0x78, 0x35, 0x78, 0x0a, + 0x16, 0x05, 0x78, 0x25, 0xcc, 0x31, 0x11, 0x2e, 0x98, 0xae, 0xab, 0x31, + 0xde, 0x31, 0x3c, 0xd2, 0xe6, 0x3c, 0x05, 0x69, 0xc5, 0xae, 0x8c, 0xf8, + 0x45, 0x38, 0x2b, 0x04, 0x95, 0xb7, 0x00, 0x61, 0xfb, 0xd2, 0x5c, 0x12, + 0x72, 0x6d, 0xdc, 0xfa, 0x96, 0x92, 0x48, 0x2a, 0xdf, 0x33, 0xf0, 0xf2, + 0x67, 0x7d, 0x51, 0x96, 0x73, 0xff, 0x00, 0x74, 0xc1, 0x9c, 0xf1, 0x36, + 0x15, 0x03, 0xeb, 0xfa, 0xfd, 0xe7, 0x93, 0x47, 0xcf, 0x58, 0xa7, 0xde, + 0x7f, 0x7e, 0x3a, 0x8b, 0xcd, 0xf8, 0x89, 0x7f, 0x7f, 0x37, 0x88, 0x78, + 0x1e, 0xf6, 0x74, 0xd1, 0x79, 0xfa, 0x8e, 0xb3, 0x1c, 0x88, 0xc6, 0x27, + 0x67, 0x57, 0x29, 0xd3, 0xff, 0x00, 0x69, 0x39, 0x96, 0x83, 0xfe, 0xe5, + 0xf9, 0xb9, 0x8e, 0xa2, 0xa3, 0x8b, 0x75, 0x70, 0xe2, 0x32, 0x17, 0x2b, + 0xb9, 0xdd, 0x79, 0xe4, 0xdb, 0x6c, 0x65, 0xf9, 0xcc, 0xe2, 0xa6, 0x07, + 0x1e, 0x3b, 0xe7, 0xfe, 0x7c, 0x75, 0xc9, 0xaf, 0xd3, 0xe7, 0x3f, 0x7e, + 0x6a, 0x27, 0x83, 0x66, 0x2f, 0x18, 0x82, 0x77, 0xd4, 0x7c, 0x6f, 0x1c, + 0xcc, 0xcb, 0x2d, 0xcc, 0x57, 0xef, 0xe6, 0xfa, 0x2f, 0xd6, 0xbf, 0x6b, + 0xf8, 0xef, 0xe7, 0xa9, 0x9e, 0xf9, 0xe3, 0xdf, 0xed, 0x1d, 0xfe, 0xbf, + 0x19, 0xe7, 0xf5, 0xe5, 0xcc, 0x9d, 0xb4, 0x44, 0x11, 0xd7, 0xaf, 0x6f, + 0x9e, 0x7e, 0xf8, 0x27, 0xd3, 0x14, 0xc2, 0xd7, 0x2f, 0x7f, 0xb5, 0xe4, + 0xeb, 0xfb, 0xd1, 0x7c, 0x96, 0x00, 0x23, 0x6c, 0xdc, 0x45, 0x13, 0xb9, + 0x7d, 0xa5, 0xf7, 0x5c, 0xec, 0x7e, 0xaf, 0x58, 0x8a, 0x8f, 0xab, 0x21, + 0x73, 0xc5, 0x47, 0x0f, 0xfe, 0xe3, 0xfb, 0xa9, 0x1c, 0x71, 0x98, 0x2c, + 0xb7, 0x1f, 0xbf, 0xb8, 0xfb, 0xf1, 0x11, 0xc6, 0x6e, 0xda, 0xd4, 0x6f, + 0xcd, 0x6b, 0x15, 0x79, 0xdf, 0x18, 0x4c, 0x95, 0x3e, 0x53, 0xb2, 0xfc, + 0x69, 0x60, 0xfc, 0x72, 0x42, 0x8b, 0x42, 0xe5, 0xc6, 0x6f, 0x6c, 0x63, + 0xef, 0xae, 0x75, 0x7e, 0x2c, 0xf6, 0xd4, 0x24, 0x4d, 0xb3, 0xde, 0x87, + 0x33, 0x11, 0xd5, 0x9a, 0xa7, 0xcd, 0xe0, 0x26, 0xb5, 0xf5, 0x0b, 0x8e, + 0xf3, 0x17, 0x66, 0x21, 0x1b, 0xbf, 0x4e, 0x17, 0xbe, 0x4c, 0x31, 0x6d, + 0xc8, 0xba, 0xf8, 0x71, 0xa3, 0x21, 0x7f, 0x53, 0x8c, 0x7a, 0x4d, 0x79, + 0xdc, 0xde, 0x75, 0x3e, 0xa3, 0xb9, 0x7a, 0x99, 0xce, 0x57, 0x36, 0xc7, + 0xdc, 0x03, 0x04, 0x0c, 0xf8, 0x6e, 0xfb, 0x9a, 0x8e, 0xd9, 0x37, 0x5d, + 0x5c, 0x1c, 0x2c, 0x4b, 0x26, 0x07, 0x09, 0x34, 0x56, 0x22, 0x88, 0x98, + 0xd9, 0xd0, 0xcf, 0xc6, 0x3e, 0x3b, 0xee, 0x49, 0x9f, 0x9f, 0x07, 0x25, + 0x0a, 0xa5, 0x2a, 0x45, 0x59, 0x07, 0xe0, 0x3f, 0x4a, 0x96, 0x22, 0x61, + 0x9e, 0x4e, 0x49, 0x97, 0xd0, 0xf3, 0x91, 0x90, 0x55, 0xe4, 0x69, 0x4c, + 0x00, 0x9a, 0x05, 0x60, 0xb1, 0x60, 0xa9, 0x91, 0xfe, 0x4b, 0xe5, 0xbc, + 0x82, 0x89, 0xb2, 0xa8, 0xb9, 0xa5, 0x87, 0x1c, 0x20, 0x10, 0x5c, 0x20, + 0x71, 0x72, 0x1d, 0x55, 0xa2, 0xe7, 0x9d, 0x15, 0x51, 0xad, 0x44, 0xb8, + 0xc9, 0x9d, 0xf6, 0xec, 0x87, 0x3d, 0xf7, 0x04, 0x47, 0x66, 0xca, 0xec, + 0xdc, 0xf2, 0x97, 0x43, 0x46, 0x82, 0xcc, 0xd0, 0xef, 0x7b, 0x12, 0x22, + 0x27, 0x83, 0x17, 0x99, 0x2a, 0x8b, 0xd4, 0xb9, 0xf3, 0x86, 0xe2, 0xf3, + 0xc2, 0xae, 0xa9, 0x8b, 0xce, 0x3e, 0x7d, 0x0e, 0x9e, 0x89, 0xe4, 0xee, + 0x37, 0x3f, 0xde, 0xcf, 0xcf, 0x9e, 0xfb, 0xbf, 0xdc, 0xfb, 0xf1, 0xe2, + 0x67, 0xd7, 0x08, 0xc5, 0xdb, 0x72, 0x9f, 0xac, 0x4c, 0x4c, 0xe6, 0x63, + 0x5c, 0xc5, 0x5a, 0x6b, 0x31, 0xda, 0x77, 0xaf, 0x1a, 0x79, 0xdf, 0x8b, + 0xf1, 0x90, 0x2b, 0xe5, 0xcf, 0x08, 0xd9, 0xd5, 0xfc, 0xfc, 0x91, 0x1e, + 0x1f, 0xae, 0x6a, 0xf7, 0x88, 0xc9, 0x66, 0x7e, 0x0a, 0x3c, 0xcf, 0x7c, + 0x95, 0x82, 0x88, 0xcb, 0xff, 0x00, 0x73, 0x33, 0x06, 0x88, 0x2e, 0x39, + 0x89, 0xf2, 0x47, 0xc3, 0xf5, 0xef, 0x9f, 0xdd, 0xf5, 0xfa, 0xe4, 0xfd, + 0xf9, 0x04, 0xe3, 0xe7, 0x59, 0x9c, 0x77, 0x9f, 0x4d, 0xcf, 0x64, 0x7b, + 0xcf, 0x8d, 0x7f, 0x33, 0xef, 0x10, 0x6e, 0x58, 0x32, 0x93, 0x8b, 0x8f, + 0xed, 0xde, 0x2a, 0xf9, 0x37, 0x17, 0xfc, 0x54, 0xdc, 0x2c, 0x7f, 0x38, + 0x92, 0xf9, 0x8c, 0x6c, 0x71, 0xe4, 0x73, 0xf3, 0x58, 0x73, 0xd5, 0xf0, + 0x62, 0x26, 0x36, 0xaf, 0xb2, 0x2a, 0x6a, 0x18, 0x23, 0xa8, 0x00, 0xbd, + 0xff, 0x00, 0x61, 0xfd, 0xff, 0x00, 0x4f, 0xd2, 0x04, 0xbc, 0xd3, 0x0c, + 0xc0, 0xd7, 0xd8, 0x33, 0xfc, 0x73, 0xb8, 0xde, 0x27, 0xb8, 0xf0, 0x18, + 0x8b, 0xaf, 0x5d, 0x73, 0xcc, 0x58, 0x3b, 0xfc, 0x18, 0xba, 0xf9, 0xaf, + 0x3c, 0x98, 0xc0, 0xbe, 0xba, 0xf9, 0xcf, 0xf7, 0xc4, 0xd2, 0x09, 0x6d, + 0xa7, 0xcf, 0x95, 0xc5, 0xdd, 0x56, 0x23, 0x97, 0xfb, 0x47, 0xcb, 0x77, + 0xdf, 0xe9, 0x37, 0x27, 0x33, 0x03, 0x11, 0x8f, 0x37, 0x13, 0xe0, 0x8a, + 0xf0, 0xd5, 0x47, 0x27, 0xef, 0x74, 0x98, 0x17, 0x77, 0x07, 0x77, 0xf9, + 0xe4, 0x4c, 0x4d, 0xc3, 0x6f, 0xad, 0x33, 0xda, 0xcc, 0x15, 0x11, 0x15, + 0x7c, 0xbc, 0x90, 0xda, 0x61, 0xa9, 0xbb, 0x8f, 0x8f, 0x4c, 0xcd, 0xdf, + 0x04, 0x40, 0xb8, 0x4b, 0xaa, 0x18, 0x83, 0xbb, 0xc3, 0x06, 0xb7, 0xc2, + 0x16, 0x66, 0x87, 0x2a, 0x90, 0x5c, 0x46, 0x9b, 0x9d, 0xb5, 0x5c, 0x96, + 0x06, 0x76, 0xc7, 0x91, 0x4d, 0xd6, 0x2e, 0x07, 0xca, 0x57, 0x04, 0xed, + 0x47, 0xcc, 0x5d, 0xc1, 0xec, 0x9c, 0x6c, 0xac, 0x70, 0x26, 0xea, 0x31, + 0x1d, 0x4c, 0xba, 0x10, 0x35, 0x64, 0x1e, 0xa7, 0x99, 0xa3, 0x26, 0x14, + 0xb2, 0xfe, 0x6e, 0xb5, 0x19, 0xa8, 0xe1, 0xc6, 0x7e, 0x4d, 0xb3, 0x2f, + 0x6f, 0x89, 0xb6, 0x25, 0x26, 0x78, 0x49, 0x68, 0x09, 0x54, 0x88, 0x03, + 0x31, 0x2e, 0x01, 0x94, 0xd7, 0x29, 0x04, 0xc9, 0xa8, 0x63, 0x87, 0x7d, + 0xd7, 0x0c, 0xd6, 0x2c, 0xee, 0x3f, 0x58, 0xfb, 0x22, 0x41, 0x26, 0x55, + 0xb7, 0xfc, 0x9c, 0xba, 0x5d, 0x26, 0x3a, 0x89, 0x39, 0x42, 0x84, 0x53, + 0x92, 0xb7, 0xda, 0x44, 0xe7, 0x9b, 0x0c, 0x49, 0x2b, 0x12, 0xf2, 0x50, + 0xa7, 0x0d, 0x10, 0x02, 0xe5, 0x14, 0x26, 0xc9, 0x43, 0x35, 0x5e, 0xff, + 0x00, 0x14, 0x6f, 0xdf, 0xef, 0xde, 0x39, 0x8e, 0xae, 0x1f, 0xa8, 0x8a, + 0xf3, 0x3b, 0xce, 0x60, 0x8e, 0x3f, 0x37, 0x87, 0x33, 0xa6, 0x22, 0x2b, + 0xaa, 0xeb, 0x13, 0xcf, 0xd3, 0xa2, 0x49, 0xee, 0x3e, 0xaf, 0xce, 0x31, + 0xc5, 0xf1, 0xd6, 0x23, 0xf7, 0xfc, 0xb3, 0x2f, 0xbc, 0xb8, 0x31, 0x9f, + 0x1f, 0xfb, 0x33, 0xdc, 0xf4, 0x72, 0x6e, 0x96, 0x8f, 0x5f, 0x5f, 0x33, + 0x47, 0xcf, 0x23, 0xe6, 0x86, 0xbd, 0x4b, 0xf5, 0xfb, 0x72, 0xff, 0x00, + 0xbf, 0xbf, 0x77, 0xfb, 0x75, 0xca, 0xea, 0x20, 0x8f, 0x9a, 0x9c, 0xf8, + 0x75, 0x8a, 0xe9, 0x78, 0x66, 0xbf, 0x9a, 0xf3, 0x5d, 0x4f, 0xe6, 0xb9, + 0xdd, 0xcc, 0xeb, 0xc7, 0x58, 0xc5, 0x7f, 0x75, 0xf7, 0xf3, 0xe7, 0xf6, + 0xeb, 0x8f, 0x97, 0xa8, 0xcf, 0x88, 0x3f, 0xb5, 0x5b, 0x1e, 0x78, 0xcf, + 0x73, 0x35, 0xba, 0xef, 0xf4, 0x25, 0xeb, 0x97, 0xfd, 0xeb, 0xfb, 0xfc, + 0xf1, 0x67, 0xf5, 0x8d, 0x02, 0xeb, 0xeb, 0x1f, 0xfb, 0xcd, 0x33, 0xb9, + 0x3f, 0xee, 0xff, 0x00, 0xf3, 0xad, 0x67, 0x3f, 0x32, 0xdf, 0xe3, 0xf5, + 0x99, 0xe7, 0x6d, 0x79, 0x8f, 0x89, 0x93, 0xc4, 0x6d, 0x63, 0xbe, 0x67, + 0xab, 0x23, 0x57, 0x97, 0x74, 0xd6, 0x37, 0x98, 0x6f, 0x86, 0x3d, 0x4f, + 0xbc, 0x4c, 0xc4, 0x4c, 0xa3, 0xf9, 0x72, 0xf2, 0x20, 0xd4, 0xb2, 0x03, + 0x78, 0x98, 0x2c, 0x3a, 0x9d, 0x8f, 0xcf, 0x25, 0x92, 0x53, 0x58, 0x9e, + 0xbf, 0x49, 0x96, 0x7c, 0x7d, 0x49, 0x8a, 0x63, 0x05, 0x30, 0x69, 0x03, + 0x5b, 0xf4, 0xfc, 0x71, 0x93, 0xcb, 0xd1, 0x47, 0xa9, 0xb8, 0xd5, 0x9a, + 0xf3, 0xcf, 0xe8, 0x98, 0x51, 0x98, 0x9a, 0x23, 0x1d, 0x98, 0x84, 0xbe, + 0x42, 0x44, 0x33, 0xef, 0x0b, 0xe1, 0xb6, 0xc9, 0x6a, 0x7e, 0xb3, 0x8a, + 0x52, 0xb2, 0xed, 0x0b, 0x35, 0x68, 0x67, 0x3d, 0xc8, 0xf0, 0x9b, 0xbc, + 0x4c, 0xe2, 0xed, 0x32, 0x63, 0x6c, 0xc1, 0x2c, 0xeb, 0x0a, 0xd4, 0x07, + 0x8b, 0x88, 0xf0, 0x84, 0x79, 0xa9, 0x4a, 0xe3, 0x71, 0x55, 0xea, 0x5b, + 0x8b, 0x88, 0xd6, 0x2e, 0xed, 0x63, 0x33, 0x35, 0xb9, 0x17, 0x30, 0x07, + 0x59, 0x3f, 0x5a, 0xdc, 0x5f, 0x22, 0x12, 0x72, 0xb5, 0x37, 0xd0, 0x4b, + 0x93, 0x35, 0x0b, 0xab, 0xae, 0x7d, 0x28, 0xb9, 0x0e, 0xf3, 0x69, 0x74, + 0xbf, 0x65, 0x07, 0x04, 0x76, 0xef, 0xcc, 0x63, 0xe2, 0x67, 0x46, 0x73, + 0x37, 0x3c, 0xb0, 0xd3, 0xe1, 0xa9, 0xcd, 0xc5, 0x45, 0x30, 0x4e, 0xc6, + 0x89, 0xe5, 0xd3, 0xa4, 0x79, 0x93, 0xdc, 0x14, 0xe3, 0x52, 0x7e, 0x26, + 0x00, 0x8a, 0x85, 0x49, 0x75, 0x1a, 0x17, 0xac, 0x40, 0xd5, 0x62, 0x0c, + 0x2d, 0x54, 0xbb, 0x46, 0x48, 0x05, 0x21, 0xdc, 0x41, 0xf6, 0x86, 0xcb, + 0x08, 0x81, 0xe0, 0x80, 0x00, 0x00, 0x3f, 0xf8, 0x48, 0xc7, 0x92, 0x4e, + 0x18, 0x01, 0x99, 0x59, 0x05, 0x69, 0x97, 0x8a, 0xa4, 0x19, 0x14, 0x23, + 0x85, 0x45, 0x32, 0xc9, 0x99, 0x1c, 0xff, 0x00, 0x1d, 0x7c, 0x4f, 0xcd, + 0xbe, 0x79, 0x26, 0x52, 0x75, 0x82, 0x1a, 0xdd, 0x5f, 0xa8, 0x10, 0xde, + 0x38, 0xb0, 0x8c, 0x16, 0x61, 0x02, 0x6a, 0x26, 0x31, 0x13, 0xa3, 0xab, + 0xef, 0xff, 0x00, 0xce, 0xcf, 0xec, 0xf9, 0xfc, 0xf3, 0xc7, 0xab, 0xeb, + 0xde, 0xff, 0x00, 0x0e, 0x39, 0x5f, 0xad, 0x75, 0xd7, 0xfd, 0xe7, 0xf4, + 0xeb, 0x5f, 0xdd, 0x6b, 0x81, 0xed, 0xfd, 0xdf, 0xef, 0xf1, 0x1c, 0xf3, + 0xf1, 0x9f, 0x5a, 0xfd, 0xff, 0x00, 0x9e, 0x6b, 0xdc, 0xf5, 0x23, 0x5d, + 0x9f, 0xdf, 0xb3, 0x9d, 0x7e, 0x0f, 0xbc, 0x7c, 0x7e, 0x39, 0xfd, 0xfe, + 0x37, 0xe3, 0xe5, 0xe7, 0xf7, 0xfb, 0xfd, 0xfd, 0xf9, 0xe1, 0xeb, 0x38, + 0x3f, 0x12, 0xff, 0x00, 0xe9, 0x7c, 0xa8, 0x23, 0x1a, 0x3a, 0xfa, 0xc6, + 0x37, 0xd5, 0x98, 0x39, 0x7d, 0xcc, 0xc7, 0xaf, 0xd7, 0x7f, 0xc7, 0x9e, + 0x6f, 0xf8, 0xd1, 0x08, 0xe3, 0x73, 0x3b, 0xf5, 0x7c, 0x88, 0xc7, 0x4f, + 0xa1, 0x63, 0x15, 0xaf, 0xee, 0x57, 0x8d, 0x45, 0x97, 0x8d, 0xf9, 0x57, + 0xfa, 0x45, 0x9d, 0x1c, 0x68, 0x71, 0x44, 0x1a, 0x2b, 0x0e, 0xa3, 0x5a, + 0x11, 0xf8, 0xe4, 0xe2, 0x63, 0xa6, 0xf6, 0x38, 0x87, 0x73, 0x38, 0xeb, + 0x8c, 0x75, 0x96, 0x9a, 0x6e, 0xd3, 0xeb, 0xff, 0x00, 0x39, 0x34, 0x33, + 0x13, 0x99, 0x33, 0x8a, 0x1a, 0x83, 0xaf, 0x52, 0xac, 0x2b, 0x92, 0x08, + 0x50, 0xfc, 0xc7, 0x6e, 0x9b, 0xf6, 0x39, 0xe6, 0xa6, 0xcd, 0xce, 0x89, + 0xd5, 0x8d, 0xfc, 0x35, 0x58, 0xe4, 0x4d, 0x9b, 0xf3, 0xa8, 0x93, 0x6e, + 0xe4, 0xae, 0xd4, 0xed, 0x67, 0x43, 0x8d, 0xf7, 0x41, 0x32, 0xec, 0xae, + 0xed, 0x33, 0x31, 0xd7, 0x8d, 0x45, 0xe2, 0x6e, 0xd6, 0x0a, 0x98, 0x9f, + 0x33, 0xa4, 0x96, 0xcf, 0x38, 0x3a, 0xaf, 0x30, 0xa3, 0x23, 0xe0, 0x9d, + 0xf2, 0x62, 0x85, 0xb5, 0x8d, 0x45, 0xb1, 0xa8, 0xb7, 0x58, 0x2f, 0x19, + 0x25, 0x8c, 0xe2, 0x22, 0xca, 0x1c, 0x0c, 0x5e, 0xa5, 0x81, 0x53, 0xab, + 0xe4, 0x28, 0x4b, 0x1d, 0xee, 0x2f, 0xc6, 0x9e, 0xe8, 0xee, 0x82, 0x5b, + 0x54, 0x60, 0xa9, 0xa3, 0x17, 0x6c, 0x45, 0x12, 0xf8, 0x98, 0x8e, 0x2a, + 0x90, 0x31, 0x8f, 0xcd, 0xc6, 0x16, 0x9c, 0x98, 0xbc, 0x72, 0x61, 0xb3, + 0x52, 0xc1, 0xc4, 0xf7, 0xb8, 0x3c, 0x55, 0xf6, 0x12, 0xa3, 0x7a, 0x21, + 0xd8, 0x55, 0xbf, 0x4f, 0xc7, 0x09, 0x4c, 0x78, 0xeb, 0x1f, 0xf4, 0x8b, + 0xbe, 0xb8, 0x06, 0x25, 0xaa, 0x93, 0x48, 0x5b, 0x00, 0xd2, 0x8a, 0x18, + 0x38, 0x17, 0xe4, 0x1f, 0x2d, 0xc0, 0xd9, 0xb2, 0x72, 0x2f, 0xfe, 0x25, + 0xe7, 0xcc, 0x30, 0x12, 0xd3, 0x39, 0x29, 0x84, 0x8c, 0x58, 0x9c, 0x92, + 0x84, 0xa9, 0xa9, 0x4d, 0x4d, 0x2d, 0x25, 0x52, 0xb2, 0x33, 0x0e, 0xa0, + 0x88, 0x35, 0xdf, 0x9e, 0x79, 0xbc, 0xff, 0x00, 0x6f, 0xbe, 0x33, 0x55, + 0x4e, 0xfe, 0xf3, 0xf5, 0x1f, 0xb6, 0xf8, 0x4b, 0xae, 0xbf, 0xf0, 0xef, + 0xea, 0x6b, 0xdf, 0x19, 0xfe, 0x75, 0xf5, 0xd7, 0xf4, 0xf3, 0xce, 0xf9, + 0xeb, 0x32, 0x7e, 0xa5, 0xfc, 0x64, 0xf3, 0xeb, 0x9a, 0xfd, 0xbf, 0xe9, + 0x7e, 0xab, 0xcd, 0x73, 0x3b, 0x8f, 0xdb, 0xfb, 0xeb, 0x8f, 0xc6, 0x62, + 0xff, 0x00, 0x6f, 0xeb, 0x84, 0xae, 0x3e, 0x27, 0xee, 0x71, 0x3d, 0xd4, + 0x44, 0x1e, 0xd7, 0x19, 0xe4, 0xa8, 0xdf, 0x8c, 0xbf, 0x39, 0x3b, 0xbf, + 0x34, 0xee, 0xbf, 0xbf, 0xdf, 0xc7, 0x31, 0x2f, 0xee, 0xbf, 0xdf, 0x47, + 0x33, 0x3e, 0x11, 0x3c, 0xd0, 0xd7, 0xcb, 0x99, 0x0d, 0x73, 0x32, 0x6b, + 0x1b, 0xf9, 0xfc, 0x27, 0xe7, 0x8d, 0x63, 0x39, 0xc5, 0x3f, 0xb4, 0xd1, + 0xd4, 0xb8, 0x49, 0xe2, 0xa4, 0x6e, 0xc2, 0xf2, 0xdf, 0xc1, 0x33, 0x8f, + 0x53, 0xea, 0xef, 0x1f, 0x77, 0xe2, 0xbc, 0xa3, 0xb3, 0x5b, 0xe4, 0xcd, + 0x54, 0x38, 0xf0, 0x89, 0xb4, 0xcc, 0x67, 0x1b, 0x93, 0xcd, 0x84, 0x51, + 0xfa, 0x63, 0x2c, 0x51, 0xbf, 0x1a, 0x9b, 0xe2, 0xbe, 0xe7, 0x4d, 0x7e, + 0x58, 0x9b, 0xa8, 0xd8, 0x95, 0xdb, 0x32, 0xec, 0x84, 0x35, 0x02, 0xbc, + 0xfe, 0xaf, 0x8e, 0xb8, 0x50, 0x5a, 0xce, 0x31, 0x80, 0x98, 0xb6, 0x01, + 0x89, 0x36, 0x61, 0x4e, 0x67, 0xb8, 0x1d, 0x55, 0x8a, 0xd8, 0x9d, 0x5a, + 0xf7, 0x8b, 0xe4, 0x47, 0x68, 0xb3, 0x1a, 0xc9, 0x93, 0xe4, 0x48, 0xf4, + 0x91, 0xc9, 0x13, 0x0e, 0xcf, 0x71, 0x0b, 0x22, 0x48, 0x93, 0x12, 0x5c, + 0x84, 0xac, 0xf0, 0xee, 0x55, 0x0b, 0x8d, 0xc9, 0x52, 0x44, 0xef, 0x2c, + 0xeb, 0xcc, 0x4b, 0x32, 0xdc, 0x63, 0x73, 0x4a, 0x2d, 0x18, 0x9f, 0x1e, + 0x37, 0x14, 0x37, 0x1b, 0x33, 0x19, 0x99, 0x60, 0x9a, 0x8c, 0x62, 0x8b, + 0x70, 0xf1, 0x88, 0x8a, 0x89, 0xef, 0x41, 0xa5, 0x89, 0xde, 0xd8, 0x57, + 0x97, 0x81, 0xd2, 0x46, 0x5a, 0x8d, 0x49, 0x14, 0x77, 0xe9, 0xdf, 0x23, + 0x29, 0xb7, 0x7e, 0x63, 0xb1, 0xc2, 0xfc, 0x56, 0xe7, 0x8a, 0x4c, 0x93, + 0x2a, 0x55, 0xcc, 0x94, 0x31, 0xde, 0xbd, 0x5f, 0x71, 0xb2, 0x3e, 0x0f, + 0x67, 0x52, 0xf6, 0xd7, 0xef, 0x89, 0x57, 0xc4, 0xe0, 0xc6, 0xa2, 0xbe, + 0x0a, 0xf8, 0x9c, 0x3c, 0x17, 0xb9, 0xed, 0x85, 0x26, 0x5c, 0x67, 0x12, + 0x42, 0x54, 0xa6, 0xd5, 0x82, 0xed, 0xc4, 0x62, 0x86, 0x6f, 0x20, 0x5c, + 0xe3, 0xcc, 0x70, 0xca, 0xa6, 0xb8, 0x40, 0xb0, 0x51, 0x16, 0x63, 0x13, + 0x42, 0x89, 0x6e, 0x76, 0x41, 0x06, 0x40, 0xae, 0xa0, 0xb4, 0x26, 0xbf, + 0xfc, 0x25, 0x32, 0xee, 0x95, 0xce, 0x10, 0xc2, 0xa1, 0x4f, 0x17, 0x8e, + 0x69, 0x4e, 0x34, 0x25, 0xee, 0xa8, 0xec, 0x50, 0xd6, 0x6c, 0xee, 0x97, + 0xca, 0x61, 0xa5, 0x4c, 0x9c, 0x08, 0xf8, 0xfe, 0xc5, 0x6b, 0xd6, 0xb9, + 0xba, 0x89, 0x8d, 0xe6, 0x3f, 0x7b, 0xd5, 0x7d, 0xf3, 0xd6, 0x6a, 0x2e, + 0x2e, 0xfc, 0x31, 0xab, 0xf8, 0xf3, 0xc9, 0xbc, 0x7c, 0x5f, 0xf7, 0xf3, + 0xca, 0x95, 0xfe, 0xfd, 0x5c, 0x7a, 0xf5, 0xc2, 0x33, 0xef, 0xc7, 0x97, + 0x5f, 0xdd, 0xdf, 0x30, 0xfb, 0xde, 0xf3, 0xb0, 0xc6, 0x7f, 0x5e, 0xa7, + 0x92, 0x04, 0xcf, 0xc7, 0x5e, 0x2e, 0x22, 0x26, 0x2f, 0x44, 0x44, 0xf3, + 0x17, 0xf1, 0xee, 0x60, 0x9d, 0xc7, 0xe2, 0xfa, 0xcf, 0x09, 0x9b, 0xd4, + 0xfe, 0xbf, 0x18, 0xc6, 0x27, 0x38, 0xdd, 0xff, 0x00, 0x6a, 0x7b, 0x8f, + 0x5a, 0xdd, 0x5f, 0x7c, 0xf1, 0x35, 0xf2, 0xb7, 0x19, 0x9c, 0x6c, 0x7f, + 0x52, 0x39, 0xfa, 0xff, 0x00, 0x67, 0xfb, 0xdf, 0x3d, 0xd3, 0x82, 0x3c, + 0xd5, 0x7b, 0xcc, 0x33, 0x0f, 0x80, 0xe2, 0xc1, 0xf8, 0xbd, 0xb1, 0x92, + 0x5c, 0x79, 0x64, 0x98, 0x99, 0x32, 0xd0, 0xbd, 0xca, 0x91, 0xf1, 0xe4, + 0x34, 0xdc, 0xb1, 0x33, 0x3a, 0x63, 0x1d, 0x6a, 0x6f, 0xc0, 0x42, 0x63, + 0xc9, 0x11, 0x98, 0xbe, 0x1a, 0x85, 0xec, 0x19, 0x88, 0x44, 0xf1, 0x5f, + 0xc4, 0x66, 0x79, 0x86, 0x35, 0x1b, 0x9b, 0x95, 0x9b, 0xc0, 0xdf, 0x57, + 0xfa, 0x3d, 0x10, 0x77, 0xa8, 0x22, 0xda, 0x4f, 0x1f, 0xdc, 0x50, 0xcc, + 0xc9, 0x10, 0x01, 0xe9, 0x02, 0x32, 0x7e, 0x0d, 0xe6, 0xe2, 0x40, 0x4a, + 0x66, 0x70, 0x97, 0x88, 0x2e, 0x6b, 0x1d, 0x1e, 0x38, 0xaf, 0x64, 0x15, + 0xe5, 0x70, 0x4f, 0x57, 0x79, 0x1c, 0xa6, 0x27, 0x90, 0xd4, 0xbd, 0xd5, + 0x6e, 0x18, 0xfc, 0x4c, 0x8c, 0x85, 0x13, 0x9e, 0x1d, 0x52, 0x31, 0x11, + 0x78, 0x66, 0x13, 0xb4, 0x97, 0xac, 0xfc, 0x65, 0xde, 0x3a, 0x4e, 0x97, + 0x10, 0xac, 0xeb, 0x17, 0x9e, 0x6d, 0x67, 0x13, 0xe5, 0x49, 0x12, 0xd4, + 0x4e, 0x27, 0xa3, 0xbe, 0x45, 0x36, 0x96, 0x3e, 0xa6, 0x7f, 0x66, 0xe1, + 0x82, 0x22, 0xaf, 0x90, 0x8c, 0x2a, 0x11, 0xb9, 0x88, 0x70, 0x4c, 0x36, + 0x2c, 0x4c, 0x7c, 0x9c, 0xed, 0xd3, 0x39, 0xce, 0x6c, 0x2a, 0x90, 0xfd, + 0x63, 0x7c, 0x19, 0x4d, 0x47, 0xe9, 0xe8, 0x89, 0x62, 0x08, 0x0b, 0xe0, + 0x1b, 0x09, 0xa3, 0xde, 0x44, 0x38, 0x3e, 0x9a, 0xc7, 0x88, 0xa9, 0x09, + 0xf9, 0x6b, 0x6e, 0x22, 0xfe, 0x3d, 0x37, 0xcc, 0x79, 0x23, 0x4b, 0xbd, + 0x31, 0x17, 0x5a, 0x67, 0x7a, 0xe3, 0x77, 0xe8, 0xf3, 0x40, 0x7a, 0xd4, + 0xd6, 0xf3, 0xa5, 0xbb, 0x96, 0x2d, 0x13, 0x1e, 0x30, 0x49, 0x3d, 0xe0, + 0xf3, 0x75, 0x33, 0xe4, 0x20, 0x96, 0x39, 0x44, 0x0e, 0x5b, 0x65, 0x80, + 0x8b, 0x1c, 0x6d, 0x10, 0x30, 0x28, 0xe2, 0x54, 0xac, 0x84, 0x18, 0x3c, + 0x43, 0x95, 0x09, 0x0c, 0x5c, 0x25, 0x80, 0x42, 0x8f, 0xfe, 0x45, 0xd0, + 0x35, 0xd3, 0x2e, 0xc3, 0x3f, 0x99, 0xa9, 0xf8, 0x88, 0xbb, 0x24, 0x59, + 0x24, 0x80, 0x5c, 0xa2, 0xb0, 0x00, 0x19, 0x94, 0x8f, 0xe6, 0x3e, 0x7f, + 0xb8, 0xef, 0x98, 0xed, 0xaf, 0x78, 0xfe, 0x66, 0xd9, 0xfc, 0x4a, 0x0d, + 0x7f, 0xeb, 0x64, 0xef, 0xf9, 0x3f, 0x5e, 0x4e, 0x7c, 0xa3, 0xd7, 0xba, + 0x8a, 0xf8, 0xa9, 0xc9, 0xcb, 0xb8, 0x7c, 0x7c, 0xe6, 0xef, 0xd5, 0x7e, + 0x79, 0xf1, 0xb2, 0xea, 0x13, 0x33, 0xf1, 0xd9, 0x94, 0x3a, 0x83, 0xf1, + 0x67, 0xee, 0x7e, 0xb1, 0xa3, 0xf5, 0x19, 0x26, 0xf7, 0x1a, 0x68, 0xf5, + 0xde, 0x5e, 0xd8, 0xc3, 0x1c, 0xfe, 0x63, 0x7e, 0xb3, 0x99, 0x9c, 0xdc, + 0x6a, 0x66, 0xf9, 0x99, 0x85, 0x31, 0xaa, 0x7c, 0xf9, 0xa2, 0x27, 0xdc, + 0x76, 0xfe, 0x5f, 0xa8, 0xbf, 0x5e, 0xfd, 0xf7, 0x1c, 0x6f, 0x43, 0x9f, + 0x5f, 0x58, 0xfe, 0x35, 0xcf, 0xfb, 0x39, 0x9f, 0xef, 0x8f, 0xeb, 0x93, + 0x4e, 0x5c, 0x7d, 0x66, 0x69, 0xbf, 0x8d, 0xb4, 0x5f, 0x51, 0x87, 0x79, + 0x25, 0x84, 0xd6, 0xba, 0xaf, 0x47, 0x21, 0x90, 0xf7, 0x16, 0x5e, 0xf1, + 0x77, 0x11, 0x34, 0x1a, 0x39, 0x2c, 0x43, 0x13, 0x66, 0xed, 0x31, 0x1d, + 0x77, 0x38, 0xc5, 0x93, 0x56, 0xc6, 0xaa, 0x61, 0xc8, 0xff, 0x00, 0x73, + 0x7b, 0xd5, 0xca, 0xb3, 0x7f, 0x13, 0x74, 0x20, 0x47, 0xdc, 0xc6, 0x74, + 0x46, 0x79, 0x09, 0x72, 0xfd, 0x15, 0xbb, 0xf1, 0xa0, 0xa0, 0x9c, 0xc4, + 0xcd, 0xe3, 0x35, 0x50, 0xa5, 0xf9, 0x94, 0x53, 0x65, 0xd0, 0xe2, 0xc7, + 0x90, 0x8a, 0x10, 0x55, 0xb8, 0xa2, 0x61, 0x99, 0xfb, 0xd0, 0xe5, 0xb7, + 0x95, 0x2e, 0xe2, 0xe9, 0x2d, 0xa6, 0x6f, 0xd5, 0xc1, 0x3d, 0xae, 0xf3, + 0x75, 0xa4, 0x95, 0xb2, 0xd9, 0x9d, 0x66, 0xe4, 0x8c, 0x17, 0x34, 0x7d, + 0x8e, 0x4b, 0x75, 0x19, 0x5e, 0xe5, 0xa9, 0xb8, 0x8e, 0x5b, 0x21, 0x69, + 0x3a, 0x87, 0x57, 0xe1, 0x99, 0xbc, 0xb5, 0x6c, 0xc7, 0x1a, 0xc2, 0x01, + 0x56, 0x42, 0xb0, 0x93, 0x57, 0xdc, 0x4b, 0x99, 0xe9, 0xe6, 0x3d, 0xfc, + 0xb3, 0x4b, 0x63, 0x45, 0xcb, 0x89, 0x86, 0xb6, 0xb4, 0x85, 0x53, 0x53, + 0x36, 0x4f, 0x5e, 0x3c, 0x0d, 0xcc, 0x21, 0x51, 0x32, 0x5e, 0x49, 0x67, + 0xa2, 0x0a, 0x5f, 0x0c, 0xc2, 0x05, 0xb6, 0x70, 0xc9, 0xde, 0x7a, 0x2b, + 0x11, 0x15, 0x19, 0x67, 0xac, 0x5c, 0xf3, 0x23, 0x3a, 0xc7, 0xaa, 0xa6, + 0x73, 0xe2, 0xd8, 0x0c, 0x6f, 0x93, 0x12, 0x4c, 0xcc, 0x2a, 0xcd, 0xc2, + 0xec, 0xad, 0x4b, 0x0f, 0x2c, 0xb0, 0x9c, 0x4a, 0x84, 0x13, 0xf3, 0xee, + 0x35, 0x39, 0x26, 0x38, 0x30, 0x93, 0x01, 0x6c, 0x42, 0xcb, 0x11, 0x98, + 0xf8, 0xbc, 0xc6, 0x46, 0xf9, 0x31, 0x33, 0x38, 0x67, 0x63, 0x9b, 0xcd, + 0x16, 0x3f, 0x33, 0x03, 0x1c, 0xa2, 0xa0, 0x51, 0x88, 0x6b, 0xc8, 0x08, + 0x51, 0x9c, 0x9c, 0xac, 0x00, 0x73, 0x47, 0x28, 0x90, 0x10, 0x23, 0x68, + 0x5b, 0xff, 0x00, 0x91, 0x74, 0x3d, 0x10, 0xa4, 0xa2, 0xc0, 0xa0, 0xc9, + 0xb0, 0x92, 0x98, 0x81, 0x23, 0xb2, 0xa1, 0xa2, 0xd2, 0x94, 0x34, 0xb9, + 0x53, 0x4c, 0xbc, 0xea, 0x81, 0x02, 0xbe, 0x88, 0xff, 0x00, 0xf2, 0xbe, + 0xa3, 0xe3, 0x7f, 0xf4, 0xe7, 0xf3, 0x71, 0x53, 0xf7, 0xee, 0x7f, 0xaf, + 0x3f, 0x45, 0xad, 0xcf, 0x5f, 0x59, 0xae, 0xa6, 0x73, 0xc9, 0xa5, 0x35, + 0x3f, 0xcf, 0x8c, 0x7c, 0x79, 0xe4, 0xf5, 0xd4, 0x9b, 0x9f, 0xdc, 0xb4, + 0xb7, 0xfe, 0xf3, 0x18, 0xc6, 0xec, 0x81, 0xaf, 0x1a, 0x3d, 0x51, 0x89, + 0xe2, 0xea, 0xae, 0xa4, 0x8d, 0xc5, 0x97, 0xf6, 0x4a, 0xe1, 0xdf, 0x09, + 0x5b, 0x1c, 0xd5, 0xf8, 0xd9, 0x03, 0x1e, 0x5d, 0xe2, 0x9e, 0x62, 0xd4, + 0x13, 0xe8, 0x7b, 0x31, 0xb7, 0x9a, 0x1d, 0x4c, 0xb4, 0xce, 0x64, 0xc1, + 0x8d, 0xfe, 0xed, 0xc8, 0xe3, 0x11, 0xa8, 0xca, 0x63, 0xaa, 0xd7, 0x61, + 0xc5, 0xbd, 0x6c, 0x91, 0xfa, 0x19, 0x37, 0xd4, 0x3d, 0xea, 0xe5, 0x12, + 0x67, 0x09, 0xfb, 0x99, 0x5c, 0xc5, 0xcd, 0xb2, 0x9c, 0x68, 0x49, 0xae, + 0xa0, 0x1c, 0xd4, 0x69, 0x90, 0xcd, 0xa4, 0x4f, 0x8e, 0x41, 0x31, 0x09, + 0x69, 0x13, 0x9d, 0xc1, 0x11, 0xef, 0x45, 0xf9, 0xa2, 0x3c, 0xf5, 0x03, + 0x31, 0x2c, 0xe4, 0xc1, 0xda, 0xfa, 0x9a, 0x79, 0x10, 0xb1, 0xb3, 0x0d, + 0x4b, 0x2a, 0xc3, 0x13, 0x5d, 0xf9, 0xcc, 0x73, 0xaa, 0x06, 0xf7, 0x75, + 0xe6, 0x62, 0xbc, 0x50, 0xbd, 0x72, 0x6d, 0x8b, 0x5b, 0xa9, 0xac, 0x54, + 0xf4, 0xe2, 0x71, 0x86, 0x08, 0xe4, 0x0e, 0xfd, 0xb3, 0x3d, 0xe5, 0xae, + 0xba, 0xe9, 0x9d, 0x71, 0x6c, 0x4f, 0x19, 0xa7, 0x07, 0x8c, 0xde, 0x51, + 0xe3, 0x17, 0x35, 0xd5, 0xeb, 0x0d, 0x8b, 0xb9, 0x9c, 0x63, 0x1a, 0xac, + 0x0c, 0x6c, 0x8a, 0x56, 0xf5, 0xdf, 0x54, 0x2e, 0x23, 0x3a, 0xc5, 0x84, + 0x1d, 0x4b, 0xd2, 0x45, 0xba, 0x71, 0x56, 0x46, 0xc5, 0xe2, 0x45, 0x53, + 0xd7, 0x89, 0x7c, 0xc9, 0x12, 0x17, 0x24, 0xc4, 0xf1, 0x45, 0x55, 0x41, + 0xf1, 0x15, 0x9f, 0x33, 0xaf, 0x36, 0x38, 0x2c, 0xbd, 0x4b, 0x7e, 0x59, + 0x82, 0x2b, 0x29, 0xe2, 0x2b, 0xb6, 0xf9, 0x70, 0xf7, 0x95, 0xf1, 0x78, + 0xf6, 0xb9, 0x2a, 0xfd, 0xf1, 0xbf, 0x90, 0xcc, 0x2d, 0x86, 0x2a, 0xd1, + 0xd1, 0x95, 0x6a, 0x2e, 0xa2, 0xef, 0x10, 0x14, 0xf7, 0xe4, 0xde, 0xd9, + 0xad, 0x68, 0xc0, 0xf6, 0xde, 0x22, 0x04, 0x9f, 0x3f, 0xf9, 0x7c, 0x58, + 0xc8, 0x67, 0xb4, 0x3b, 0x70, 0xf5, 0x14, 0x46, 0x21, 0xdf, 0x09, 0xb3, + 0x43, 0xdc, 0xd3, 0x97, 0x7f, 0x08, 0x57, 0xd7, 0x2d, 0x6a, 0xa2, 0x06, + 0x09, 0xb5, 0x07, 0x8a, 0x33, 0x07, 0x03, 0xcb, 0x10, 0xbd, 0xf3, 0xae, + 0x34, 0x92, 0x10, 0x20, 0xe4, 0x8b, 0x85, 0x27, 0xb0, 0x0e, 0x54, 0xa4, + 0xc0, 0x8f, 0xfe, 0x6c, 0xb0, 0x02, 0x46, 0x18, 0xc0, 0x00, 0xb3, 0x23, + 0xb2, 0x56, 0x50, 0xa5, 0x0a, 0x15, 0x2a, 0xc8, 0x73, 0x12, 0x5b, 0xd7, + 0xe6, 0xd8, 0x8d, 0xd6, 0x77, 0x8b, 0x8f, 0x3c, 0xc1, 0x30, 0x18, 0xc3, + 0x3f, 0x9c, 0xab, 0x9f, 0x2b, 0xcb, 0x40, 0x8d, 0x55, 0xc5, 0x8c, 0x75, + 0x50, 0x5e, 0x3c, 0x44, 0xd7, 0x17, 0x31, 0x6f, 0xb7, 0x75, 0x9f, 0x7a, + 0x1c, 0x9e, 0xce, 0x68, 0xf8, 0xcc, 0x0c, 0x3a, 0xee, 0x6a, 0x3c, 0xb7, + 0xea, 0xf1, 0x3e, 0x34, 0x75, 0x29, 0x22, 0xe5, 0xa8, 0x4e, 0x8f, 0x28, + 0x49, 0xf1, 0x82, 0x88, 0x56, 0xe3, 0xbb, 0xcf, 0xbd, 0x72, 0xa3, 0xd7, + 0x99, 0x6e, 0x36, 0xbb, 0x1d, 0x3e, 0x97, 0x93, 0x70, 0x66, 0xb2, 0xd4, + 0x40, 0xd5, 0x33, 0xef, 0x3b, 0x94, 0xae, 0x2e, 0x62, 0xe2, 0xbc, 0x5e, + 0xe7, 0xfe, 0xeb, 0xe7, 0x8d, 0xe4, 0x36, 0x90, 0xa9, 0x04, 0x3d, 0xc6, + 0xf2, 0xc4, 0xe3, 0x73, 0xc5, 0x30, 0x89, 0xd4, 0xcf, 0x47, 0xb2, 0x85, + 0x9d, 0x77, 0x9e, 0x24, 0xe9, 0x1e, 0x41, 0xb6, 0x61, 0xce, 0x05, 0x82, + 0x37, 0x39, 0xe1, 0x44, 0x5b, 0x19, 0x21, 0x8d, 0x9d, 0x38, 0x7e, 0x2a, + 0x42, 0x79, 0x96, 0x81, 0xb8, 0xbc, 0x26, 0xb2, 0xdb, 0xf9, 0x62, 0xa6, + 0x1e, 0x46, 0x0d, 0xe4, 0xcd, 0xa4, 0xf5, 0x37, 0x17, 0x18, 0xc6, 0x90, + 0xe0, 0xcc, 0x55, 0xb2, 0xac, 0x75, 0x46, 0x35, 0xa6, 0xbb, 0xe4, 0xa8, + 0xb1, 0x16, 0x74, 0xb6, 0x65, 0x88, 0x9a, 0xbc, 0xf7, 0xed, 0x70, 0xa6, + 0x24, 0x93, 0x56, 0xe0, 0xeb, 0xc5, 0xe1, 0xc4, 0x3c, 0x66, 0xa6, 0x71, + 0x2e, 0xbc, 0x46, 0x7e, 0x16, 0xdb, 0x27, 0x80, 0xd3, 0x31, 0x04, 0x7a, + 0x22, 0x19, 0x7b, 0x9b, 0x8d, 0x34, 0xbc, 0x55, 0xde, 0xc3, 0xa2, 0x13, + 0x7a, 0xef, 0xd7, 0x6d, 0x21, 0x14, 0x4d, 0x39, 0xf4, 0x4d, 0xdc, 0x96, + 0xdf, 0x8f, 0xcf, 0x21, 0xb5, 0x0b, 0x18, 0x7c, 0x16, 0xc1, 0x96, 0x7b, + 0x89, 0xc5, 0xf6, 0xcf, 0xb6, 0x21, 0x2c, 0x9c, 0xb7, 0x11, 0xad, 0x4e, + 0x77, 0xdd, 0x59, 0xa8, 0xce, 0xea, 0x64, 0x74, 0x36, 0x81, 0x31, 0x1f, + 0x13, 0x57, 0x96, 0x72, 0x4d, 0x69, 0xb4, 0xed, 0xdc, 0x6f, 0x27, 0x22, + 0x8b, 0x90, 0x31, 0xe1, 0x59, 0x41, 0xca, 0x13, 0xe0, 0x9f, 0x02, 0x32, + 0x93, 0x05, 0x57, 0x7a, 0xcb, 0x16, 0xd1, 0x5a, 0x63, 0xcb, 0xc0, 0xa0, + 0x88, 0x95, 0x92, 0x89, 0xc3, 0xb8, 0xbb, 0xaf, 0x97, 0x97, 0xd2, 0xe6, + 0xa6, 0x1a, 0xfd, 0xcb, 0x2c, 0xf1, 0x3d, 0x5c, 0x92, 0xe5, 0x13, 0xb9, + 0x24, 0xb9, 0x19, 0xde, 0x3e, 0x71, 0x7f, 0xda, 0xbd, 0xde, 0xcd, 0x0e, + 0x26, 0x22, 0xf2, 0x70, 0x5a, 0xc8, 0x5e, 0x2c, 0x98, 0x8c, 0x30, 0x39, + 0xba, 0xc7, 0x55, 0x2d, 0x9c, 0xc8, 0xa9, 0x02, 0xdb, 0x81, 0x25, 0xbc, + 0xb2, 0x9c, 0x98, 0xe3, 0x2e, 0x70, 0x0c, 0x71, 0x23, 0x54, 0x4b, 0xff, + 0x00, 0xa0, 0x46, 0x19, 0x8d, 0xdc, 0x11, 0x02, 0xe2, 0x8c, 0x70, 0x89, + 0x70, 0x4b, 0x51, 0x68, 0xa0, 0x3c, 0x80, 0x4e, 0xa3, 0x91, 0xc4, 0x89, + 0x24, 0x60, 0xa4, 0x99, 0x20, 0x98, 0x8b, 0x81, 0xeb, 0x1d, 0xb0, 0xd9, + 0x6d, 0x93, 0x18, 0xf8, 0x82, 0x23, 0xac, 0xb8, 0x9b, 0x39, 0x31, 0xe5, + 0x0b, 0xc4, 0xf8, 0xcc, 0xdc, 0x2b, 0x13, 0xad, 0x12, 0x70, 0x43, 0x71, + 0x87, 0x50, 0xd7, 0x9b, 0x66, 0xf3, 0x75, 0xad, 0xbb, 0x4f, 0x33, 0x36, + 0x10, 0x55, 0xe2, 0x9b, 0x42, 0x59, 0xf5, 0xc9, 0x7f, 0x50, 0x59, 0xdf, + 0x73, 0xb9, 0x8a, 0x8c, 0x35, 0x43, 0x37, 0xe6, 0x61, 0x17, 0xa5, 0x88, + 0x7f, 0xf3, 0xa0, 0x58, 0x07, 0x95, 0x2c, 0x5f, 0x8f, 0x64, 0xea, 0x48, + 0x96, 0xe6, 0x89, 0xa8, 0xda, 0xc3, 0x2a, 0x2e, 0x3a, 0x49, 0xf5, 0x33, + 0xd5, 0xa0, 0x77, 0x33, 0xc9, 0x64, 0x58, 0xeb, 0xd2, 0x4c, 0x1e, 0x2d, + 0x9d, 0xd4, 0xdc, 0x31, 0xc9, 0x7e, 0x43, 0x35, 0x29, 0x93, 0x4c, 0x7c, + 0xc4, 0x54, 0xe7, 0x9a, 0xb2, 0x40, 0xc9, 0x13, 0x7a, 0x2f, 0xd6, 0x81, + 0x26, 0xa2, 0x39, 0x25, 0xed, 0x86, 0x5e, 0xec, 0x68, 0x64, 0x8d, 0xe3, + 0xcc, 0x17, 0xc3, 0x13, 0x99, 0xa5, 0x65, 0xa7, 0x40, 0xee, 0x6b, 0xdd, + 0xc4, 0x34, 0x4b, 0x2b, 0x57, 0x74, 0xc3, 0x51, 0x20, 0xed, 0xc6, 0x26, + 0x27, 0x69, 0xc4, 0x90, 0xee, 0xa7, 0xbc, 0x59, 0xe2, 0xd8, 0x8c, 0x4a, + 0x77, 0xcc, 0x2f, 0x7b, 0xa9, 0x81, 0x2e, 0xac, 0x89, 0xcf, 0x5a, 0x91, + 0x82, 0xc5, 0x9c, 0xbe, 0x3c, 0xb6, 0x79, 0xeb, 0xde, 0xb8, 0xd3, 0x70, + 0xe8, 0xdb, 0x5d, 0x92, 0x12, 0xd5, 0xcc, 0xd4, 0x07, 0x05, 0x5d, 0x60, + 0x23, 0x4e, 0xa1, 0x88, 0x91, 0xbc, 0x34, 0x4c, 0x78, 0x9b, 0x88, 0x8b, + 0x4f, 0x4c, 0x46, 0xea, 0x3b, 0x9c, 0xd4, 0xb2, 0x72, 0x2b, 0x6c, 0xbd, + 0x67, 0x1f, 0x22, 0xcc, 0x8e, 0x31, 0x22, 0xd1, 0x31, 0xf1, 0x24, 0x81, + 0x87, 0xcf, 0xdc, 0x63, 0x77, 0xcb, 0x86, 0x2e, 0xb2, 0xf8, 0xbd, 0x2c, + 0x38, 0xcc, 0x63, 0x13, 0xc7, 0x0b, 0x33, 0x71, 0xac, 0x18, 0xad, 0x4c, + 0x7b, 0xa8, 0xdb, 0xc9, 0x2e, 0xa3, 0x70, 0x17, 0xde, 0x7a, 0x20, 0xc4, + 0x65, 0xd7, 0x33, 0x9b, 0x8a, 0xc0, 0x30, 0x12, 0xd5, 0x1b, 0x31, 0x31, + 0x75, 0x5c, 0x21, 0x21, 0x26, 0xe6, 0x77, 0x3a, 0x30, 0xb6, 0xc5, 0xf6, + 0xf8, 0xe1, 0x74, 0x28, 0xb8, 0x9b, 0x09, 0xce, 0xfb, 0xaa, 0xea, 0x37, + 0x1c, 0x25, 0xed, 0x27, 0x5a, 0x18, 0xaf, 0x75, 0x52, 0xf5, 0x1c, 0xa8, + 0x47, 0x71, 0x8f, 0x32, 0x07, 0xa9, 0x25, 0x79, 0x31, 0xce, 0x96, 0x83, + 0x1a, 0x7b, 0x44, 0xdc, 0xc9, 0x7c, 0xdf, 0x51, 0xcb, 0x88, 0x0c, 0xcb, + 0x5d, 0xcd, 0xd4, 0x53, 0x11, 0x8f, 0x33, 0xc9, 0x7b, 0x86, 0x08, 0xb9, + 0x92, 0x01, 0x19, 0x99, 0x80, 0xcd, 0x84, 0x54, 0xf2, 0x9e, 0x10, 0x35, + 0x8a, 0x06, 0x64, 0xc4, 0x16, 0x59, 0x66, 0x03, 0xc6, 0x81, 0x23, 0xec, + 0x04, 0xf7, 0x94, 0x1d, 0x1f, 0xfd, 0x90, 0x41, 0x25, 0x28, 0x22, 0x05, + 0x43, 0xd6, 0x7f, 0xf0, 0xde, 0xf3, 0xca, 0x2c, 0x00, 0x34, 0x08, 0xd2, + 0x44, 0xb0, 0x22, 0x7e, 0x70, 0x58, 0x5e, 0x63, 0x79, 0x26, 0xbb, 0x7a, + 0xbb, 0xe2, 0xb9, 0xa1, 0x8a, 0xb2, 0x73, 0x9c, 0x56, 0xc6, 0x60, 0x96, + 0x22, 0x6b, 0x8b, 0x05, 0x12, 0x1b, 0xc9, 0x83, 0xe8, 0x5c, 0xdb, 0x2c, + 0xcc, 0xe3, 0x89, 0x64, 0x32, 0x19, 0x6b, 0x0c, 0xcd, 0xf7, 0x9b, 0xc1, + 0xb4, 0x89, 0xe5, 0xde, 0xed, 0x3f, 0x5c, 0xe6, 0x72, 0x6b, 0x50, 0x4d, + 0x0e, 0xdb, 0x08, 0x8e, 0xaa, 0xb7, 0x78, 0x6b, 0xce, 0x34, 0x1c, 0x6e, + 0x3b, 0xc6, 0x40, 0xa7, 0xb6, 0x65, 0x67, 0xb6, 0x3c, 0xf3, 0x38, 0xb6, + 0x81, 0x52, 0xaf, 0xc6, 0x5e, 0xe1, 0x9e, 0xb2, 0x83, 0x87, 0xa5, 0x00, + 0x22, 0x35, 0x8e, 0xd9, 0x93, 0x52, 0x1a, 0x83, 0x91, 0x17, 0x65, 0x97, + 0x7f, 0xac, 0xc4, 0x5d, 0xce, 0x71, 0x6b, 0x3c, 0x6f, 0x4c, 0x76, 0xcb, + 0x0c, 0x93, 0x33, 0x50, 0x04, 0x6c, 0xac, 0xf2, 0x6e, 0x87, 0x77, 0x58, + 0x59, 0x01, 0x90, 0x65, 0xd3, 0x3b, 0x39, 0x15, 0x1d, 0x5b, 0xa3, 0x73, + 0x2f, 0x8e, 0xd6, 0x1e, 0xb9, 0x7d, 0xfc, 0xb6, 0x43, 0x2c, 0x2c, 0x5b, + 0x51, 0xb9, 0x7d, 0x71, 0x3e, 0xe5, 0x31, 0x12, 0x51, 0x57, 0xee, 0x05, + 0x2a, 0x70, 0x1c, 0x27, 0x01, 0x1b, 0xf3, 0xe0, 0x14, 0x62, 0x26, 0x31, + 0x48, 0xd9, 0x7c, 0x85, 0xfb, 0x04, 0xf0, 0x78, 0xe8, 0x66, 0x93, 0xee, + 0xe2, 0x65, 0xf2, 0xd1, 0x99, 0xac, 0x56, 0x86, 0xf1, 0x08, 0x1c, 0xaa, + 0x9b, 0xc5, 0x41, 0x15, 0x8b, 0xb1, 0x4a, 0x71, 0xbb, 0xe4, 0xc0, 0x35, + 0x3f, 0x38, 0x88, 0x27, 0xeb, 0x03, 0x93, 0x13, 0x31, 0x96, 0x72, 0xc4, + 0x1f, 0x82, 0xc6, 0xb0, 0x4f, 0xbd, 0xeb, 0x93, 0x89, 0x2c, 0x0d, 0xe8, + 0xb0, 0x9f, 0xfb, 0xb6, 0x0d, 0xf0, 0x1a, 0x63, 0xcc, 0xd2, 0xd6, 0x58, + 0xf3, 0xda, 0x74, 0xae, 0xf9, 0x93, 0xae, 0x8c, 0xea, 0x7b, 0xd6, 0xa1, + 0xfb, 0xbb, 0x9c, 0xc6, 0x3b, 0x73, 0x8c, 0x4b, 0xe3, 0x18, 0x98, 0xa0, + 0xc7, 0x37, 0x11, 0xea, 0x73, 0xf7, 0xfb, 0x54, 0xa6, 0x2b, 0x93, 0x60, + 0x3d, 0xd7, 0x75, 0x6c, 0x7a, 0xce, 0xa2, 0x47, 0x8a, 0xba, 0x0f, 0x2e, + 0x32, 0xd5, 0x36, 0x65, 0x88, 0x7c, 0x95, 0xc6, 0x60, 0x31, 0x0a, 0xde, + 0xe6, 0x08, 0xf1, 0xa7, 0xff, 0x00, 0x4e, 0x2b, 0xd7, 0xed, 0xea, 0x0a, + 0x26, 0x27, 0xc3, 0x3a, 0xcf, 0x19, 0x99, 0x7b, 0xf3, 0xea, 0xed, 0x75, + 0xdf, 0xcd, 0x3c, 0x36, 0x13, 0xb3, 0xf7, 0xcb, 0x38, 0x73, 0xea, 0x39, + 0x6b, 0x8a, 0x0b, 0x67, 0x84, 0x96, 0x2d, 0x6a, 0x18, 0x88, 0xc9, 0xc1, + 0x54, 0x9a, 0xa6, 0xf8, 0x80, 0x58, 0xc0, 0x5b, 0x5f, 0xfd, 0xcf, 0xf5, + 0x8b, 0x20, 0x68, 0x0a, 0xaa, 0x7a, 0x5e, 0x68, 0x80, 0xd9, 0x61, 0x8a, + 0x42, 0x51, 0x14, 0x49, 0x00, 0x09, 0x71, 0x40, 0x21, 0x0c, 0x66, 0x59, + 0x30, 0xa4, 0x51, 0x42, 0xff, 0x00, 0x36, 0x04, 0xc3, 0xaf, 0xd2, 0x34, + 0x44, 0xe1, 0x89, 0x82, 0x51, 0x06, 0xae, 0x79, 0x45, 0x63, 0x66, 0xcf, + 0x19, 0xfb, 0x44, 0x27, 0x8c, 0xf3, 0x0a, 0x5d, 0xea, 0x94, 0xdf, 0xcc, + 0x48, 0xc5, 0xb9, 0x71, 0x97, 0xd9, 0x26, 0x33, 0x2f, 0x52, 0x77, 0x20, + 0xd9, 0x1d, 0x50, 0x9c, 0x61, 0xf0, 0xbd, 0xe4, 0xb6, 0xc6, 0xa2, 0x09, + 0xfa, 0x0f, 0x75, 0x33, 0xe6, 0xca, 0x66, 0x63, 0x7a, 0x99, 0x66, 0xd0, + 0xef, 0x13, 0xa1, 0x9c, 0xb6, 0xd0, 0xf5, 0x9f, 0x59, 0xba, 0x59, 0x66, + 0x48, 0xdc, 0x39, 0x93, 0xa8, 0x9b, 0xf6, 0x45, 0xcf, 0x94, 0xd3, 0xc1, + 0xba, 0xb6, 0xd7, 0x4a, 0x54, 0x64, 0x75, 0xa3, 0xb2, 0xf3, 0xc6, 0x5a, + 0x68, 0x14, 0xfc, 0x1f, 0xc9, 0x8f, 0xce, 0x39, 0x98, 0xee, 0xd9, 0x9a, + 0x49, 0x67, 0x54, 0x66, 0xa3, 0x6a, 0xd1, 0xcc, 0xca, 0x4a, 0xc6, 0x6d, + 0x49, 0x22, 0x7d, 0x93, 0x59, 0xdb, 0x11, 0x01, 0x74, 0xf9, 0xf3, 0x9e, + 0xdc, 0xfe, 0x33, 0x1d, 0xcf, 0x32, 0xcd, 0xf9, 0x8d, 0xd4, 0x4d, 0xc6, + 0x59, 0xee, 0x66, 0x20, 0x5b, 0xa1, 0xde, 0x26, 0x88, 0x89, 0xa9, 0x8f, + 0x73, 0x86, 0x3a, 0xf1, 0x2e, 0x24, 0x45, 0x7c, 0xc3, 0x39, 0xbf, 0x18, + 0x67, 0x6e, 0x33, 0xc7, 0x2c, 0x3d, 0x74, 0xd7, 0xc4, 0x66, 0x33, 0x4e, + 0x69, 0xbe, 0x0e, 0x3e, 0x83, 0xb6, 0x2c, 0xf3, 0x2d, 0xde, 0x86, 0x2f, + 0x13, 0x46, 0x24, 0x75, 0x17, 0x24, 0x5b, 0xbc, 0x5d, 0x24, 0x40, 0xbc, + 0x8d, 0xfb, 0xef, 0x3e, 0x8a, 0xca, 0x74, 0x45, 0xe6, 0xb8, 0xb5, 0xba, + 0xa9, 0x9e, 0xcc, 0x7a, 0x19, 0x8f, 0x0a, 0x54, 0xbc, 0xcf, 0xbe, 0xd9, + 0xce, 0x83, 0x2c, 0xf5, 0x2d, 0xf5, 0x8e, 0x41, 0x04, 0x17, 0x86, 0xee, + 0x5c, 0x45, 0xbd, 0x59, 0xee, 0x37, 0x0e, 0x67, 0x76, 0xf9, 0x26, 0xcb, + 0xeb, 0x1f, 0xf3, 0x3c, 0xef, 0x70, 0xc4, 0x3f, 0x2f, 0xc7, 0x92, 0x7d, + 0x6f, 0x91, 0xde, 0x2d, 0x36, 0x95, 0x8f, 0xfb, 0xe7, 0xa3, 0x82, 0xe0, + 0x9c, 0xc9, 0x2c, 0xc2, 0xf5, 0x8a, 0x9f, 0x07, 0xea, 0xf1, 0x8f, 0xd3, + 0xcf, 0x59, 0xfc, 0x3e, 0x3c, 0x70, 0xb9, 0xf1, 0xa2, 0xfe, 0x2e, 0xf2, + 0x9e, 0x62, 0x1f, 0x1c, 0xea, 0xfd, 0x7c, 0xfe, 0x67, 0x3d, 0x52, 0xc9, + 0xce, 0xe7, 0x08, 0xad, 0xc1, 0x53, 0x50, 0x7e, 0x3c, 0xf5, 0x5c, 0x89, + 0x87, 0x31, 0x89, 0x09, 0xbc, 0x10, 0x06, 0xc3, 0xe8, 0x85, 0x5f, 0x37, + 0x06, 0x0e, 0x0a, 0x62, 0x9e, 0xe6, 0x0f, 0xfe, 0xce, 0x03, 0x7f, 0x88, + 0x12, 0x57, 0x23, 0x28, 0x44, 0x45, 0x38, 0x29, 0x9d, 0x09, 0xbe, 0xc0, + 0x1b, 0x1a, 0xa1, 0x48, 0x97, 0x28, 0xe5, 0x34, 0x22, 0x1f, 0x65, 0x72, + 0xb3, 0xdf, 0x16, 0x66, 0x63, 0xe9, 0x75, 0x70, 0xe3, 0x51, 0xd5, 0x45, + 0xb9, 0xa9, 0xc2, 0x21, 0xf7, 0xa3, 0xd9, 0xdb, 0x6c, 0xd9, 0xdf, 0x3d, + 0x16, 0x05, 0xcc, 0x53, 0x2b, 0x13, 0x11, 0xec, 0x98, 0x96, 0x1c, 0x72, + 0x3e, 0xce, 0x99, 0xa6, 0x89, 0x8b, 0x72, 0x59, 0x51, 0x59, 0xae, 0x5b, + 0x7b, 0x6a, 0x99, 0xa0, 0x47, 0xb9, 0x95, 0x3f, 0x0c, 0xda, 0xf1, 0xc6, + 0x22, 0xf1, 0x2b, 0xdf, 0xb3, 0x33, 0xd6, 0x33, 0x7c, 0x9f, 0x18, 0xc7, + 0xc3, 0xf1, 0xde, 0x4e, 0xcc, 0xeb, 0x97, 0x29, 0x5f, 0x10, 0xff, 0x00, + 0xc9, 0x9a, 0xaf, 0x5e, 0x39, 0x16, 0xc6, 0x59, 0xce, 0x77, 0x13, 0xb9, + 0x6e, 0xbb, 0xce, 0x4e, 0x2d, 0x3e, 0xe4, 0xa5, 0x91, 0xd5, 0xe7, 0x01, + 0x61, 0x89, 0xbc, 0x72, 0xf5, 0x0c, 0x6f, 0x2b, 0x35, 0x23, 0x3d, 0xa5, + 0xa8, 0xa8, 0x56, 0x79, 0xd5, 0xff, 0x00, 0x18, 0x2f, 0xf6, 0xa9, 0x94, + 0x76, 0x72, 0xe8, 0xba, 0xf3, 0x34, 0xb2, 0x63, 0xd9, 0xf4, 0x6f, 0x8f, + 0x5e, 0xee, 0x20, 0x7a, 0x6a, 0x4a, 0x19, 0x9a, 0xa7, 0xec, 0x6b, 0x42, + 0x58, 0xb3, 0x2f, 0xe5, 0xc5, 0x41, 0xfb, 0x4c, 0x85, 0x8f, 0x6f, 0x49, + 0x98, 0x88, 0x87, 0xdc, 0x53, 0x31, 0x83, 0x5d, 0x9e, 0x74, 0x47, 0xba, + 0x83, 0x70, 0x05, 0x5d, 0x19, 0xe5, 0x76, 0xe3, 0xc4, 0xce, 0xbf, 0x9f, + 0xc7, 0x9e, 0x38, 0xaf, 0x2e, 0x7e, 0xa5, 0xef, 0xe3, 0xd1, 0x7c, 0x62, + 0x5f, 0x83, 0x7f, 0x39, 0x0f, 0xd0, 0x8b, 0xf8, 0xcf, 0x44, 0xc4, 0x60, + 0x2b, 0x3a, 0xc3, 0xe3, 0x7f, 0x89, 0xb8, 0xd7, 0xf3, 0xd6, 0x74, 0xf7, + 0x90, 0x9b, 0x2a, 0x67, 0x7b, 0x96, 0x7d, 0x84, 0xeb, 0x6f, 0x90, 0x12, + 0xf3, 0xc0, 0xcc, 0x91, 0xe7, 0x78, 0x61, 0xc6, 0x0d, 0xe6, 0x21, 0x35, + 0x7b, 0x6a, 0x73, 0x15, 0x8f, 0x7e, 0x49, 0x87, 0xbb, 0x8e, 0x47, 0xfe, + 0x54, 0x41, 0x9d, 0x62, 0x33, 0x3f, 0x8e, 0x7b, 0x1c, 0xaf, 0x74, 0x47, + 0xa5, 0xab, 0xa8, 0x23, 0x19, 0x96, 0x3b, 0x74, 0xbf, 0x2d, 0x1e, 0xa8, + 0x17, 0xbc, 0x8e, 0xb9, 0xfb, 0xfb, 0xfd, 0x3f, 0xb9, 0x77, 0xc5, 0x7b, + 0x69, 0x23, 0xe9, 0x99, 0x7d, 0x7c, 0x86, 0x15, 0xc5, 0x70, 0x90, 0xd9, + 0x81, 0xa4, 0x2e, 0x24, 0x37, 0x45, 0x8e, 0x3b, 0x4c, 0xce, 0x45, 0xf0, + 0x83, 0x12, 0x9b, 0x23, 0xc0, 0x34, 0xaa, 0xca, 0xa3, 0x05, 0x02, 0x70, + 0x00, 0xff, 0x00, 0x42, 0x74, 0x31, 0xb3, 0x20, 0x80, 0x14, 0x09, 0x85, + 0x3a, 0x99, 0xa8, 0xc1, 0x4d, 0x92, 0x8e, 0x58, 0x07, 0xb9, 0xe2, 0xe8, + 0xc0, 0xd7, 0x50, 0xf9, 0xcc, 0x3e, 0xe1, 0x1d, 0x47, 0x31, 0x03, 0xe6, + 0x6b, 0x03, 0xae, 0xcd, 0xcf, 0xb9, 0x07, 0x75, 0xaf, 0x5e, 0x4b, 0x3e, + 0x13, 0xc5, 0x5b, 0xb8, 0x1e, 0x29, 0x03, 0x3e, 0x82, 0x65, 0x92, 0x96, + 0x6e, 0x96, 0xb3, 0x9c, 0x9c, 0x5c, 0xaa, 0xb3, 0x9e, 0xfd, 0x54, 0xdd, + 0xcc, 0xd4, 0x43, 0x55, 0xa0, 0x9f, 0x71, 0x66, 0x0d, 0x40, 0x48, 0x66, + 0x25, 0x9c, 0xf3, 0xea, 0x16, 0x34, 0x4e, 0x8a, 0xb0, 0x8c, 0xbe, 0xcf, + 0x0f, 0x23, 0x33, 0xeb, 0xd5, 0xe6, 0x0f, 0xeb, 0xa9, 0x8a, 0x2a, 0xfc, + 0xeb, 0xc5, 0xdf, 0xec, 0x6e, 0x3c, 0x72, 0x22, 0x37, 0x37, 0x1e, 0xff, + 0x00, 0xba, 0x7e, 0x93, 0x92, 0x55, 0x32, 0x4f, 0x89, 0x7f, 0x32, 0xba, + 0xf3, 0x44, 0x09, 0x31, 0xe3, 0xa6, 0x2e, 0x1a, 0x9f, 0x17, 0x55, 0x8e, + 0xf3, 0x38, 0x88, 0x47, 0xf7, 0xe9, 0x48, 0x8c, 0x3e, 0x77, 0xc8, 0x1c, + 0xfa, 0x0c, 0x8c, 0xe2, 0x66, 0xba, 0xdd, 0x2a, 0x43, 0xa9, 0xf8, 0x2a, + 0x4b, 0x6a, 0xe5, 0xf4, 0xc2, 0xe6, 0x6b, 0x49, 0x44, 0x49, 0x48, 0x20, + 0x93, 0x48, 0xcb, 0x6d, 0xc7, 0x9b, 0x3e, 0x23, 0x87, 0x61, 0x11, 0xa4, + 0x9f, 0x9d, 0x97, 0x9d, 0x1b, 0x39, 0x5f, 0xda, 0xbf, 0xcf, 0xed, 0xc6, + 0xb0, 0xa8, 0x12, 0xc1, 0x81, 0x96, 0x5d, 0xe0, 0xcf, 0xeb, 0x1c, 0xd7, + 0x89, 0xc5, 0xe7, 0xd7, 0xf1, 0xfb, 0x92, 0xdc, 0xb7, 0xdd, 0xf6, 0xea, + 0xbf, 0xe7, 0x30, 0x1b, 0xf9, 0xb6, 0xb1, 0x6b, 0xd7, 0xc6, 0xf9, 0xff, + 0x00, 0x62, 0x5e, 0xa3, 0xd6, 0xa0, 0xfa, 0xf1, 0xcc, 0xdc, 0xdd, 0x4c, + 0xda, 0x4b, 0xed, 0x75, 0x93, 0x1f, 0x17, 0x2d, 0xae, 0x76, 0xf6, 0x1f, + 0x9f, 0x8e, 0xfe, 0xf8, 0x7e, 0xfd, 0x6a, 0xfe, 0x20, 0xde, 0x27, 0xef, + 0x97, 0x91, 0x48, 0x4b, 0xdc, 0x5e, 0x21, 0xdc, 0x77, 0xc9, 0xad, 0x93, + 0x12, 0x2e, 0x7e, 0xbe, 0xe0, 0x98, 0xb5, 0x88, 0x78, 0x95, 0x38, 0xb0, + 0xc4, 0xe6, 0x7c, 0x6b, 0x4c, 0x81, 0xb9, 0xe1, 0x83, 0xbf, 0x7e, 0xb5, + 0x91, 0xf6, 0x1d, 0x80, 0x64, 0x8a, 0x0e, 0x70, 0x89, 0xd8, 0x83, 0x11, + 0x73, 0x71, 0x3a, 0x28, 0xe5, 0x28, 0xb8, 0x17, 0x46, 0xcc, 0x9b, 0x21, + 0x95, 0x73, 0xfd, 0x02, 0xbc, 0xb9, 0x2d, 0x7d, 0xcf, 0xf5, 0x6e, 0x1c, + 0x82, 0xfa, 0xcf, 0x99, 0x54, 0x24, 0x74, 0xe4, 0x4a, 0x04, 0x9a, 0xa2, + 0x12, 0x41, 0xb9, 0x00, 0xdc, 0x42, 0x41, 0xb5, 0xcc, 0x0d, 0x47, 0x86, + 0x19, 0xc4, 0x69, 0xf9, 0x9d, 0x90, 0x46, 0xb7, 0x28, 0xcc, 0xcb, 0x71, + 0x8c, 0xd6, 0x46, 0x72, 0x9e, 0x7a, 0xa3, 0xf4, 0x88, 0x3d, 0xb4, 0xed, + 0xd3, 0x22, 0xa3, 0x6e, 0x24, 0x99, 0x1d, 0xb4, 0x24, 0x75, 0x0b, 0x9c, + 0xcc, 0x3e, 0x6e, 0xf8, 0x86, 0x6b, 0x39, 0xdf, 0x87, 0xdc, 0xd4, 0xbe, + 0xf5, 0xcf, 0x43, 0x50, 0xcf, 0x4e, 0xfe, 0x3f, 0xf7, 0xbe, 0x7b, 0x85, + 0x67, 0x7b, 0xf7, 0x53, 0x8a, 0xc8, 0xea, 0xe7, 0x8c, 0x38, 0x4c, 0x45, + 0xb7, 0x19, 0x3e, 0x50, 0x88, 0x30, 0xd6, 0xe9, 0x89, 0x60, 0x01, 0xfd, + 0x3e, 0x63, 0xa8, 0xd6, 0x03, 0xdf, 0x78, 0xa8, 0xcf, 0x8e, 0xa1, 0xb9, + 0xdd, 0x7c, 0xdf, 0x3f, 0xbb, 0x8f, 0xde, 0xbe, 0xf8, 0xeb, 0xc5, 0xbd, + 0x33, 0x10, 0xd0, 0x44, 0xd7, 0x5a, 0xa3, 0x9f, 0xf9, 0xfb, 0xf2, 0x67, + 0x31, 0xf2, 0x4f, 0xac, 0xce, 0x20, 0xf2, 0x79, 0xe4, 0xdc, 0xcf, 0x85, + 0x49, 0x8f, 0x57, 0xe2, 0x9b, 0x90, 0xac, 0xc9, 0x31, 0x37, 0x13, 0xd3, + 0x9f, 0xc6, 0x96, 0x37, 0xf3, 0x3c, 0x57, 0xcb, 0x7f, 0xd5, 0xf8, 0xff, + 0x00, 0x9c, 0x4a, 0x71, 0xd4, 0x57, 0x93, 0x24, 0xfc, 0xfc, 0x37, 0xc9, + 0x8f, 0x9f, 0xbc, 0x93, 0xf1, 0xbf, 0x1e, 0x78, 0x59, 0x74, 0xb1, 0x16, + 0x55, 0xdc, 0xef, 0xf8, 0xf9, 0x39, 0xae, 0xa6, 0x9b, 0x8e, 0x9c, 0x37, + 0xa0, 0xfb, 0xd9, 0x4d, 0x3b, 0xa1, 0xa8, 0xbd, 0x7c, 0x7a, 0x33, 0xf9, + 0xe2, 0xc5, 0xdb, 0xdb, 0xe3, 0xf7, 0x8d, 0x75, 0xe0, 0x57, 0x87, 0x9d, + 0x4f, 0x74, 0x2d, 0x5f, 0xd4, 0xc6, 0xf9, 0x44, 0x64, 0xfa, 0xc7, 0x9d, + 0x56, 0xda, 0xfc, 0xc7, 0x09, 0xcc, 0xd7, 0x43, 0x57, 0xef, 0x31, 0xdd, + 0x78, 0x2d, 0xe4, 0x26, 0xfc, 0xe6, 0x3b, 0x87, 0x34, 0x86, 0x36, 0xd7, + 0x1a, 0x9d, 0x45, 0x45, 0xe6, 0x93, 0xf1, 0xe1, 0xf2, 0x21, 0x1c, 0x3b, + 0x92, 0x23, 0x06, 0x03, 0x2f, 0x6b, 0xa6, 0x26, 0xf8, 0xf0, 0xc6, 0xab, + 0x2a, 0x95, 0x81, 0x78, 0xb0, 0xd3, 0x2c, 0xe2, 0x97, 0x81, 0xea, 0xe8, + 0x6f, 0xe0, 0xb5, 0xfe, 0x92, 0x03, 0x46, 0x8d, 0x97, 0x84, 0xac, 0x01, + 0x0c, 0xbc, 0x12, 0x34, 0x80, 0x0b, 0x12, 0x15, 0xde, 0x03, 0x67, 0x4b, + 0x71, 0xf2, 0xc4, 0xdb, 0xf3, 0x31, 0xff, 0x00, 0xbd, 0x34, 0x3b, 0xf1, + 0x35, 0x3f, 0xd7, 0xfb, 0x1a, 0xf8, 0x75, 0xe4, 0xc5, 0xf6, 0xce, 0x57, + 0x67, 0xef, 0x4f, 0x3b, 0xed, 0x67, 0x3d, 0xfa, 0x12, 0xa6, 0x5d, 0xe8, + 0x27, 0x99, 0x0f, 0x94, 0x8f, 0x89, 0x9d, 0x31, 0x10, 0xf9, 0x9b, 0xe6, + 0x32, 0xd5, 0xce, 0xa9, 0xef, 0x38, 0x89, 0xdc, 0x6a, 0x1e, 0x79, 0x72, + 0xff, 0x00, 0xee, 0x3e, 0x6a, 0xaf, 0xba, 0xe4, 0xfb, 0x8d, 0x47, 0xb2, + 0xd3, 0xbf, 0x03, 0xa2, 0xf9, 0x53, 0x89, 0xcf, 0xf7, 0xba, 0xf7, 0xd4, + 0xf0, 0x6d, 0x51, 0x7e, 0x50, 0x26, 0x5f, 0xe7, 0x7c, 0x98, 0xfa, 0xcf, + 0xbf, 0xec, 0x3a, 0x09, 0xe4, 0xb7, 0x73, 0x39, 0xed, 0x6e, 0xe7, 0xe6, + 0xfb, 0xbe, 0xc3, 0x8f, 0xaf, 0x8d, 0x4e, 0xb3, 0x2f, 0xf5, 0xf1, 0x13, + 0x7a, 0x98, 0xc1, 0x3f, 0x70, 0xaf, 0x3f, 0x7f, 0xd9, 0xef, 0xfb, 0xbf, + 0x3c, 0x3f, 0x9f, 0xef, 0xef, 0xe3, 0x93, 0x73, 0xfb, 0x56, 0x71, 0x17, + 0x5e, 0xf8, 0xc1, 0x87, 0xca, 0x9a, 0xcd, 0xf7, 0xaa, 0xaf, 0x8a, 0xe6, + 0xab, 0x6b, 0x91, 0xf1, 0x3f, 0xf9, 0x5e, 0xec, 0x93, 0xe7, 0x3e, 0x2f, + 0x2c, 0x7c, 0x6c, 0x49, 0x82, 0x3c, 0x93, 0x07, 0x89, 0xee, 0x1c, 0xdd, + 0x55, 0x11, 0x4c, 0x3b, 0xdf, 0x23, 0xfa, 0xe3, 0xeb, 0xd9, 0xfc, 0x45, + 0xaf, 0xeb, 0xf9, 0x27, 0xbe, 0x44, 0x8f, 0xc1, 0x8c, 0xe7, 0xce, 0x3c, + 0x3e, 0x72, 0x72, 0x27, 0xeb, 0x3e, 0x23, 0x67, 0x8c, 0xd8, 0x45, 0xea, + 0x65, 0x96, 0x75, 0x7e, 0xe7, 0xdf, 0xdd, 0xc4, 0x4c, 0x7c, 0xf3, 0xbf, + 0x61, 0xf7, 0x18, 0x86, 0x4f, 0xc7, 0x7c, 0xd7, 0xf5, 0x70, 0xe7, 0x5a, + 0x96, 0x43, 0xdf, 0x20, 0x6e, 0x1c, 0x21, 0x69, 0x52, 0x6c, 0xe8, 0x32, + 0x4e, 0x26, 0x47, 0xfe, 0xa5, 0x3f, 0x47, 0x18, 0xb0, 0x2f, 0xfa, 0x61, + 0xd8, 0xe4, 0x8e, 0x54, 0xe2, 0xa5, 0x1c, 0x3a, 0x85, 0xb5, 0x74, 0xea, + 0xf7, 0x04, 0xa4, 0x99, 0x84, 0xfc, 0x59, 0x1a, 0xe4, 0x64, 0x04, 0x3c, + 0x8c, 0xc0, 0xac, 0xc1, 0x06, 0x87, 0x95, 0x33, 0xd3, 0x39, 0xce, 0x3e, + 0x67, 0xcf, 0xcc, 0x1c, 0xd7, 0x9b, 0x82, 0x62, 0x75, 0xe7, 0xbb, 0x7a, + 0x22, 0xf4, 0xe6, 0x68, 0x57, 0x49, 0xea, 0xe2, 0xad, 0x7c, 0x6f, 0xbe, + 0x4e, 0xe3, 0x6c, 0xe7, 0xa1, 0xa9, 0x99, 0x67, 0x3f, 0x42, 0x59, 0xc9, + 0x98, 0xa0, 0x89, 0x4e, 0xf7, 0xbb, 0xf8, 0xfd, 0xaf, 0x9e, 0x5f, 0xcb, + 0x7e, 0xe9, 0xbf, 0xc9, 0xf8, 0xe1, 0xbc, 0x4e, 0xbd, 0x16, 0xfc, 0xfe, + 0xc7, 0x98, 0xe4, 0xdb, 0x06, 0x73, 0xfa, 0xf8, 0x34, 0x59, 0xea, 0x89, + 0xe5, 0xd1, 0xa5, 0x35, 0xf1, 0x3f, 0x1b, 0xf9, 0xdf, 0x35, 0x31, 0xe6, + 0x75, 0xd4, 0xe3, 0xe2, 0x6f, 0xae, 0x51, 0x1f, 0x58, 0xfe, 0x3f, 0xe1, + 0xcc, 0x53, 0xe7, 0xc6, 0xf4, 0x7b, 0x59, 0xf3, 0xef, 0x99, 0xbe, 0xc9, + 0x26, 0x27, 0x39, 0x33, 0x37, 0x0e, 0xf9, 0x2d, 0x5c, 0xa7, 0xdc, 0x6b, + 0xfb, 0xe1, 0x80, 0x93, 0x9d, 0xc3, 0x90, 0xb3, 0xef, 0xe7, 0xf4, 0xeb, + 0x9e, 0x9d, 0x57, 0xe7, 0x64, 0xd2, 0x7a, 0xde, 0x6b, 0x89, 0xea, 0xcf, + 0xe4, 0xba, 0x7f, 0x7a, 0x78, 0x5f, 0xcc, 0x44, 0xd5, 0x53, 0x7d, 0x83, + 0x0d, 0x62, 0x36, 0xf3, 0xaf, 0x3f, 0x1f, 0xa9, 0x9c, 0x53, 0xe7, 0xae, + 0x7e, 0x7c, 0x63, 0xfb, 0xf8, 0xf3, 0xdf, 0x19, 0xfa, 0xfe, 0xf6, 0x17, + 0x0c, 0x76, 0xfa, 0xe5, 0x02, 0x15, 0x06, 0x6d, 0x4f, 0xcd, 0xd4, 0x67, + 0x51, 0x1c, 0xde, 0x5d, 0xe2, 0xbd, 0x3b, 0xfe, 0x1b, 0xea, 0x8a, 0xff, + 0x00, 0xc0, 0xdb, 0x7a, 0xf9, 0xef, 0x21, 0xc9, 0x5e, 0xfc, 0x1f, 0x1b, + 0x18, 0x9b, 0xdc, 0x0f, 0xa2, 0x79, 0x1d, 0xfa, 0xa9, 0xf3, 0xb9, 0xeb, + 0x2f, 0xc9, 0x70, 0x72, 0x66, 0x04, 0xa3, 0xeb, 0xb3, 0x54, 0x28, 0xac, + 0x80, 0xa0, 0x89, 0xf6, 0xf8, 0xbc, 0x42, 0x19, 0xf3, 0xf3, 0xa4, 0x3a, + 0xf6, 0xd1, 0xf5, 0x65, 0x97, 0xc2, 0x53, 0x42, 0xbf, 0xe9, 0xda, 0x0e, + 0x79, 0x81, 0x12, 0x49, 0x7d, 0x9c, 0x4c, 0xf3, 0x93, 0x68, 0x12, 0xcd, + 0x2c, 0x02, 0xec, 0x69, 0xea, 0x88, 0x46, 0xaa, 0xf1, 0x15, 0xf9, 0x7f, + 0x5f, 0xbe, 0x2d, 0x91, 0x1a, 0xf8, 0xc7, 0x73, 0x5e, 0x67, 0xca, 0x47, + 0x2f, 0x71, 0xe5, 0x73, 0x2b, 0x7d, 0xb3, 0x57, 0x12, 0x43, 0xda, 0xf3, + 0xfb, 0x57, 0xf9, 0xff, 0x00, 0x91, 0xa9, 0x6b, 0x94, 0x75, 0x99, 0xc7, + 0xe7, 0xc3, 0xf7, 0xcf, 0xeb, 0xcf, 0x14, 0xd1, 0xef, 0x6c, 0xd7, 0x8c, + 0x97, 0xf8, 0xab, 0xea, 0x30, 0xdf, 0xaf, 0x0d, 0xcc, 0xfe, 0x27, 0xa9, + 0xff, 0x00, 0xb7, 0x8f, 0xc6, 0xa7, 0xa2, 0xb9, 0x3f, 0xc6, 0x3e, 0x3a, + 0xfc, 0xe7, 0x2f, 0x7c, 0x26, 0xa7, 0xc6, 0xbc, 0xf4, 0xa8, 0xc7, 0xbb, + 0x8e, 0x79, 0xba, 0x9f, 0xef, 0x7f, 0xaf, 0x92, 0x4e, 0x45, 0xc5, 0x4c, + 0x5e, 0x22, 0xc9, 0x9c, 0xed, 0x0c, 0x2e, 0xce, 0xe3, 0xe6, 0x65, 0x7b, + 0xed, 0xfe, 0xfd, 0x6f, 0x93, 0x9f, 0x1b, 0xae, 0xb2, 0xfc, 0xc9, 0xec, + 0xfa, 0x19, 0xf1, 0x0e, 0xcf, 0xf9, 0x67, 0xe3, 0x8c, 0x58, 0x98, 0x96, + 0x46, 0x1c, 0x20, 0xcc, 0xc6, 0xbf, 0x9f, 0x01, 0x7f, 0xfb, 0x3a, 0x9c, + 0xb7, 0x9f, 0x8a, 0xcc, 0x56, 0x23, 0x59, 0x89, 0xdf, 0x71, 0xfc, 0xb2, + 0xe6, 0x7b, 0xe4, 0xc8, 0xf5, 0xf9, 0xfa, 0x4a, 0x8c, 0x9b, 0xc2, 0x70, + 0xc4, 0x98, 0xfe, 0xc7, 0x82, 0x63, 0xc7, 0xeb, 0xc6, 0x33, 0x31, 0x5f, + 0x4c, 0x4f, 0x52, 0xf7, 0x1b, 0x3e, 0xf9, 0xfa, 0xfa, 0x53, 0xbb, 0x7a, + 0x26, 0xb1, 0xd5, 0x63, 0x8f, 0xeb, 0xf8, 0x8c, 0x6b, 0x1e, 0xe6, 0xdc, + 0x23, 0xc0, 0x6f, 0xcc, 0xdb, 0xe4, 0xc1, 0x86, 0x95, 0x65, 0x84, 0xc1, + 0x72, 0xf1, 0x5d, 0x34, 0x37, 0xe2, 0x43, 0xab, 0xea, 0xe6, 0xaf, 0xe2, + 0x27, 0xf5, 0x60, 0x14, 0x08, 0xae, 0x09, 0x90, 0xc4, 0xb8, 0xa7, 0xc5, + 0xe2, 0x70, 0xe8, 0x5b, 0xa3, 0x3c, 0x13, 0x72, 0xff, 0x00, 0xab, 0x1d, + 0xdd, 0x40, 0xb1, 0x24, 0x2c, 0x1e, 0x30, 0xa8, 0x8d, 0x45, 0x86, 0x51, + 0x5c, 0x51, 0x18, 0x81, 0xae, 0x05, 0x6c, 0x51, 0x65, 0xfc, 0x65, 0x28, + 0x10, 0x28, 0xcc, 0xa3, 0x9e, 0x9b, 0x24, 0x8c, 0x67, 0xbf, 0xee, 0x1d, + 0xf3, 0xcc, 0xbd, 0x7e, 0x3f, 0x4b, 0xfd, 0xb5, 0x07, 0x3d, 0x91, 0xf5, + 0xfd, 0x7e, 0x61, 0xf1, 0xc8, 0x27, 0xdc, 0x7d, 0xfd, 0xf8, 0x23, 0xd7, + 0x9e, 0x76, 0xff, 0x00, 0x7f, 0x8f, 0xcc, 0x46, 0xf5, 0xcf, 0x8d, 0x66, + 0x7f, 0x6d, 0xfc, 0x5f, 0xc4, 0xf1, 0x9d, 0x11, 0x2c, 0x6d, 0xa5, 0x4a, + 0xbf, 0xdf, 0x13, 0xc8, 0x83, 0xe2, 0x7a, 0xdb, 0xd7, 0x6e, 0x58, 0xce, + 0x3c, 0xea, 0xbf, 0xe7, 0x8e, 0x7f, 0xe7, 0x9b, 0xfe, 0xfb, 0xaa, 0xbe, + 0x66, 0x3f, 0x68, 0x9e, 0xe7, 0x64, 0xf5, 0x92, 0x8e, 0x13, 0xf2, 0x67, + 0x73, 0xe7, 0xe6, 0x3a, 0x98, 0x10, 0x39, 0xe4, 0xfd, 0x98, 0x22, 0x62, + 0xae, 0x3c, 0x17, 0x3e, 0x39, 0xe7, 0xb0, 0xfe, 0xcc, 0xc6, 0xff, 0x00, + 0xef, 0x0f, 0xde, 0xe3, 0xbb, 0xcb, 0x72, 0x43, 0xed, 0x2e, 0x71, 0x9b, + 0xdd, 0x52, 0x59, 0xbf, 0x12, 0x0b, 0x7a, 0xa3, 0xcb, 0x91, 0x2e, 0x3b, + 0x33, 0x51, 0xdf, 0x5e, 0xe6, 0x37, 0xa3, 0x97, 0x77, 0x36, 0xf5, 0x38, + 0xf8, 0x33, 0x87, 0x1f, 0xb1, 0x5d, 0xcb, 0xdd, 0xfd, 0xe4, 0xfe, 0x87, + 0x47, 0x31, 0x41, 0x80, 0x9c, 0xc4, 0xee, 0x18, 0x9f, 0xd5, 0x2b, 0xcf, + 0x2e, 0x4b, 0xf0, 0xc9, 0xf9, 0xbc, 0x31, 0xe3, 0x6e, 0xe1, 0x87, 0x6c, + 0xe2, 0xa0, 0xbd, 0x39, 0xd4, 0x66, 0x3f, 0x78, 0xe5, 0xfe, 0x99, 0xdf, + 0x7e, 0x71, 0x8b, 0xce, 0x79, 0x39, 0x02, 0xb2, 0x6b, 0x3f, 0x18, 0x61, + 0x45, 0x84, 0xa7, 0x11, 0x2f, 0x3d, 0xcc, 0x36, 0x2e, 0x2b, 0xe4, 0xe7, + 0xa4, 0x39, 0x01, 0x85, 0x84, 0xc0, 0x39, 0xb3, 0xeb, 0x5f, 0xea, 0xd8, + 0x58, 0x32, 0x28, 0x6a, 0x9c, 0x00, 0x9e, 0x3e, 0x65, 0x79, 0x41, 0xb3, + 0x95, 0x0c, 0xcb, 0x21, 0x52, 0x61, 0x46, 0x11, 0x2b, 0x0c, 0xa3, 0x39, + 0x21, 0xe8, 0xfe, 0x4a, 0xb7, 0x9a, 0xba, 0x63, 0x38, 0xb5, 0x63, 0x71, + 0x3e, 0x2c, 0x84, 0x99, 0x67, 0x97, 0xa0, 0xdf, 0xe5, 0x2f, 0x5e, 0xd3, + 0x6e, 0xf9, 0x53, 0x5f, 0xdf, 0x2e, 0x89, 0xfc, 0xfd, 0x73, 0x1f, 0x57, + 0x98, 0xac, 0xff, 0x00, 0x7f, 0x58, 0xe4, 0xea, 0x9c, 0x7c, 0x24, 0xff, + 0x00, 0x1f, 0x7e, 0x62, 0x20, 0xaf, 0x14, 0x7f, 0x7e, 0x37, 0xc4, 0x1d, + 0x7e, 0xd5, 0xeb, 0x5d, 0x84, 0x68, 0x98, 0x42, 0x27, 0xf3, 0x5a, 0x63, + 0xff, 0x00, 0x1e, 0xb1, 0x2e, 0xb1, 0x70, 0x61, 0xc4, 0xb1, 0x93, 0x6f, + 0x96, 0x3f, 0x6d, 0x1c, 0x5f, 0xef, 0xbc, 0x6a, 0x7e, 0xb7, 0xf3, 0xca, + 0xc5, 0x4c, 0x5e, 0xa7, 0xb7, 0xe5, 0x2f, 0xf8, 0xe6, 0x36, 0xde, 0xd9, + 0x9f, 0x97, 0xe8, 0x26, 0xf5, 0x7c, 0xab, 0xbd, 0xf7, 0x89, 0x2d, 0xf1, + 0x67, 0xb9, 0xbe, 0xf8, 0x39, 0xc6, 0x63, 0xe7, 0x0f, 0x59, 0x5e, 0x89, + 0xce, 0xf8, 0xc6, 0x7a, 0x95, 0xf1, 0x4d, 0xf9, 0xaf, 0x9b, 0xb3, 0x1c, + 0xf1, 0x57, 0x9c, 0xcb, 0x59, 0xfb, 0x8d, 0xd1, 0xca, 0x1c, 0xee, 0xba, + 0x67, 0xde, 0x6e, 0x6a, 0xb3, 0x66, 0x38, 0xe2, 0xff, 0x00, 0x19, 0x31, + 0x2e, 0xf0, 0xba, 0x98, 0xe2, 0x4f, 0xf6, 0xbb, 0xc4, 0x87, 0x17, 0x36, + 0x0c, 0x45, 0xc5, 0x54, 0xff, 0x00, 0xee, 0xab, 0xc7, 0x3c, 0x12, 0x62, + 0x63, 0x15, 0x35, 0x31, 0x92, 0x75, 0xf6, 0x5f, 0x2a, 0xe6, 0x9c, 0xd3, + 0x8d, 0x4e, 0x28, 0x9c, 0xd5, 0xee, 0xab, 0x91, 0xa3, 0x6d, 0xb5, 0xe6, + 0x62, 0xea, 0xeb, 0xc7, 0xdb, 0xc8, 0x94, 0x6a, 0x0b, 0x5c, 0xfb, 0x04, + 0x33, 0x2c, 0x49, 0xce, 0xf1, 0xe8, 0xac, 0xe0, 0x60, 0xae, 0x74, 0x83, + 0xfd, 0x71, 0x3b, 0xc2, 0x8b, 0xb9, 0xc1, 0x2d, 0xf2, 0x02, 0x49, 0x9e, + 0x09, 0x07, 0xca, 0x1b, 0x3c, 0x26, 0x58, 0x03, 0x24, 0xa7, 0x10, 0x25, + 0xa1, 0x5d, 0x89, 0xcc, 0x4c, 0xb4, 0x17, 0x18, 0x5f, 0xaf, 0xc6, 0x2b, + 0xf7, 0xef, 0x8b, 0x07, 0x56, 0xc5, 0x6d, 0xe8, 0xdb, 0xdf, 0x71, 0xcc, + 0x78, 0x8f, 0xce, 0x3d, 0xcf, 0x97, 0x27, 0xa7, 0x8e, 0xbc, 0xa7, 0x7a, + 0xba, 0xfa, 0x9e, 0xbe, 0xf9, 0xdd, 0x53, 0xe6, 0x49, 0x7b, 0x2b, 0xe6, + 0x32, 0xc7, 0x98, 0xef, 0x7f, 0x51, 0xe4, 0xbf, 0x19, 0x3c, 0xd5, 0xbc, + 0x9a, 0xe9, 0x98, 0xd3, 0xb8, 0xfe, 0xcc, 0x6f, 0x87, 0xe2, 0xc8, 0xae, + 0xd9, 0xf2, 0xce, 0x09, 0xcc, 0x33, 0x7c, 0x15, 0x18, 0xed, 0x86, 0x67, + 0x38, 0x99, 0xc4, 0x49, 0x59, 0xaf, 0xb7, 0xbf, 0x15, 0x8b, 0xa2, 0xe6, + 0xe0, 0x82, 0x2e, 0xbf, 0x1c, 0xcd, 0x25, 0xc3, 0xd3, 0xe1, 0x8c, 0xf8, + 0xcc, 0x53, 0xec, 0xe1, 0x39, 0xce, 0x27, 0x38, 0xf4, 0xd6, 0x9c, 0x12, + 0xe8, 0xb9, 0x16, 0x3d, 0xfe, 0x0d, 0xdc, 0x4f, 0x60, 0xf6, 0xc4, 0x54, + 0x3c, 0xae, 0xd6, 0x34, 0x3e, 0xea, 0x06, 0xa3, 0x10, 0xd6, 0x0b, 0xae, + 0x56, 0x05, 0x21, 0x88, 0x22, 0xb3, 0xde, 0x4d, 0xb9, 0x7e, 0x47, 0x8f, + 0x6c, 0x4d, 0x54, 0x62, 0xfb, 0xdc, 0x29, 0xe2, 0xaa, 0x1b, 0x33, 0xe7, + 0xbb, 0x5a, 0x2b, 0xe3, 0xc9, 0xf0, 0xf7, 0xcf, 0xce, 0xfc, 0xd4, 0x41, + 0x55, 0x33, 0x79, 0xfc, 0x63, 0xe2, 0x1f, 0xc3, 0xab, 0x86, 0x27, 0x5b, + 0x9a, 0x75, 0x06, 0x14, 0x8a, 0x8d, 0xbe, 0x27, 0xdc, 0x42, 0x13, 0x92, + 0xaa, 0x39, 0x9c, 0x3e, 0x37, 0x75, 0x72, 0xe4, 0xfd, 0x92, 0xe5, 0xa1, + 0x1c, 0x9d, 0x4e, 0x29, 0x30, 0xb3, 0x67, 0x86, 0xfb, 0x8c, 0xc7, 0x09, + 0xb0, 0x5b, 0x4a, 0x89, 0x9c, 0x22, 0x27, 0x09, 0x91, 0x12, 0xbc, 0x22, + 0x07, 0xc8, 0x10, 0x04, 0x39, 0x2d, 0xeb, 0x49, 0x0f, 0xbe, 0xb4, 0x37, + 0x69, 0x26, 0xc0, 0xdf, 0x98, 0x9f, 0xf6, 0x29, 0x92, 0x24, 0x0b, 0xc3, + 0xa3, 0x25, 0x83, 0x24, 0x6e, 0x22, 0x90, 0x60, 0x25, 0x09, 0x14, 0x12, + 0x05, 0x5c, 0x0d, 0x29, 0x11, 0x81, 0x80, 0x84, 0x11, 0x4a, 0x46, 0x19, + 0x12, 0x29, 0x00, 0x45, 0x43, 0xcc, 0xfa, 0x0b, 0xf0, 0x9a, 0xcf, 0xb9, + 0x99, 0x22, 0x2f, 0x92, 0xf5, 0x3e, 0xba, 0x7c, 0xc9, 0x0e, 0x1f, 0xd3, + 0xc4, 0x66, 0xdf, 0x79, 0xa9, 0x6a, 0x3e, 0xf5, 0xba, 0xe8, 0x2b, 0x5d, + 0x19, 0xaf, 0xd7, 0x04, 0xb0, 0x7a, 0xf8, 0x1f, 0x9a, 0xd4, 0x4f, 0x99, + 0xea, 0x58, 0xa9, 0xd7, 0xc7, 0x29, 0x25, 0x98, 0xd7, 0x82, 0x33, 0x18, + 0x9b, 0x59, 0xef, 0xcd, 0x02, 0x96, 0xc3, 0x12, 0x7a, 0x20, 0x96, 0x30, + 0xde, 0x63, 0x0e, 0x27, 0x9a, 0x21, 0x22, 0x3c, 0x39, 0xf7, 0x18, 0x9f, + 0x11, 0x88, 0xd1, 0x3a, 0x67, 0xf3, 0xbf, 0x67, 0x69, 0x8b, 0x1f, 0x04, + 0xf1, 0x8a, 0xa6, 0x72, 0xcb, 0x08, 0x4c, 0xac, 0xe3, 0x37, 0x13, 0xf5, + 0x1c, 0xf1, 0xe2, 0xba, 0xde, 0x6f, 0xd1, 0xe6, 0xe3, 0x71, 0x3d, 0x50, + 0xf5, 0x9b, 0x1b, 0x7b, 0xef, 0x33, 0x5d, 0xc9, 0xcf, 0x04, 0xe6, 0xdf, + 0x31, 0x6e, 0xb4, 0x93, 0x11, 0x99, 0x2c, 0xe3, 0xaf, 0x16, 0xdb, 0x01, + 0x6c, 0xe2, 0xf1, 0x46, 0xa6, 0xa2, 0x0e, 0x44, 0xc7, 0xcd, 0x35, 0x35, + 0x12, 0x91, 0xdb, 0xfb, 0xf5, 0xcc, 0x7c, 0xd5, 0x19, 0x5b, 0x4b, 0x9a, + 0xce, 0xe0, 0x94, 0xa8, 0x9e, 0x4d, 0x5d, 0xe9, 0xcc, 0x15, 0xe6, 0x7d, + 0x2e, 0x3b, 0xdf, 0x12, 0x4b, 0x33, 0x07, 0x70, 0x93, 0x7f, 0x12, 0x5a, + 0xe3, 0x3e, 0x73, 0x29, 0x6f, 0xbb, 0x08, 0xa8, 0x7a, 0x73, 0x24, 0x52, + 0xec, 0xe1, 0x99, 0x8b, 0x3d, 0x7c, 0xee, 0x32, 0x61, 0x54, 0x7a, 0xe3, + 0x64, 0xbb, 0xf5, 0xbb, 0x43, 0xa3, 0x73, 0xb8, 0x92, 0x67, 0x85, 0x4f, + 0x2c, 0xcc, 0xa5, 0xdc, 0x1b, 0x04, 0xdc, 0x65, 0x78, 0xb4, 0x68, 0x8c, + 0x7d, 0xe9, 0x0a, 0xb4, 0x90, 0x87, 0xfb, 0x00, 0x5d, 0x53, 0xf8, 0xf4, + 0x04, 0x11, 0x29, 0x43, 0x85, 0x92, 0xad, 0x16, 0xa3, 0x21, 0x72, 0xe7, + 0x02, 0x08, 0x56, 0x32, 0x26, 0x06, 0x14, 0x45, 0xc0, 0xb8, 0x60, 0x16, + 0x13, 0x35, 0x71, 0xbd, 0x1a, 0x7e, 0x67, 0xa3, 0x77, 0x71, 0xc5, 0x09, + 0xbb, 0xcd, 0xaf, 0xfd, 0xac, 0xcd, 0x56, 0x6a, 0x9e, 0x40, 0xdc, 0x4d, + 0xa8, 0xdc, 0x1d, 0x54, 0xed, 0xdd, 0x0f, 0xd4, 0x9e, 0x71, 0x51, 0x88, + 0xb3, 0xea, 0x57, 0x31, 0xdd, 0x65, 0xe7, 0xcc, 0x3a, 0x8b, 0xce, 0xdf, + 0x0c, 0x8b, 0x35, 0xe7, 0x0f, 0x2e, 0xf5, 0x75, 0xdb, 0x88, 0xc0, 0x9f, + 0x2e, 0x03, 0x9f, 0x15, 0x72, 0x56, 0x59, 0xee, 0x32, 0xb0, 0x55, 0x87, + 0x9e, 0x54, 0x38, 0x72, 0xc6, 0x3e, 0xfe, 0x33, 0x3d, 0xdd, 0xc7, 0x33, + 0x89, 0xb7, 0x30, 0x7c, 0x3e, 0x43, 0x4f, 0x8c, 0xf6, 0xfa, 0x37, 0xe7, + 0x50, 0xe9, 0x26, 0x82, 0xe7, 0x64, 0x72, 0x5a, 0xb5, 0xa9, 0x88, 0x71, + 0xad, 0xee, 0x36, 0xaf, 0x88, 0x5e, 0x2e, 0x25, 0xc3, 0xf5, 0x03, 0x98, + 0x9b, 0x94, 0x31, 0xf0, 0xf1, 0x87, 0xdd, 0x79, 0xc3, 0x38, 0x36, 0x45, + 0x49, 0x12, 0xc6, 0xd3, 0x8d, 0xc4, 0x4b, 0x69, 0x15, 0xd3, 0xbb, 0x31, + 0x57, 0x32, 0x79, 0x17, 0x8b, 0xfb, 0xfa, 0x25, 0x85, 0x74, 0xe6, 0xed, + 0x84, 0xc5, 0xb1, 0x12, 0x1d, 0x55, 0x2d, 0x3d, 0xd9, 0xb9, 0xaf, 0x7a, + 0xc3, 0xcc, 0x38, 0xab, 0x2a, 0x2b, 0x15, 0xd4, 0xe2, 0x55, 0xc9, 0x5a, + 0x98, 0x5b, 0x90, 0xd9, 0x9c, 0x49, 0x96, 0x61, 0x95, 0xa3, 0xa6, 0xb0, + 0xf3, 0x13, 0x02, 0x40, 0x6f, 0xc2, 0xf6, 0x0c, 0x51, 0x12, 0xfd, 0x57, + 0x0c, 0x8d, 0xed, 0x5b, 0x22, 0x61, 0x87, 0x38, 0xf6, 0x1f, 0x33, 0xc9, + 0xb0, 0x54, 0x5b, 0xac, 0x91, 0x77, 0x10, 0x05, 0x64, 0x6c, 0x70, 0x94, + 0x8a, 0x08, 0x7d, 0x0c, 0xa7, 0x49, 0x95, 0xdc, 0x05, 0x91, 0x4a, 0xbc, + 0xd9, 0x04, 0x84, 0xa0, 0x3f, 0xda, 0x0b, 0x61, 0x66, 0x00, 0xd8, 0x02, + 0xa5, 0x78, 0xf3, 0xc6, 0x96, 0x85, 0x44, 0x98, 0xe4, 0x48, 0x08, 0x82, + 0xaf, 0x33, 0x8a, 0x1a, 0x95, 0x4d, 0x21, 0x2d, 0x91, 0x66, 0x96, 0xc6, + 0x28, 0xe6, 0x0b, 0x67, 0xc9, 0xe7, 0xe4, 0x0c, 0x8c, 0xce, 0xe0, 0xa2, + 0x78, 0x10, 0x3d, 0xc4, 0xaf, 0x51, 0xf0, 0x93, 0x0b, 0x39, 0x49, 0xaa, + 0x88, 0xd4, 0x93, 0xd6, 0x7d, 0x99, 0x5e, 0xda, 0x85, 0xd6, 0x34, 0x3f, + 0x2b, 0x2d, 0x77, 0xb1, 0x5c, 0x64, 0x6b, 0xf3, 0xbc, 0x69, 0x08, 0x89, + 0xaf, 0x99, 0x02, 0x23, 0x2c, 0x95, 0x98, 0x85, 0x8e, 0x62, 0x6e, 0x8a, + 0x18, 0xc7, 0x61, 0x14, 0xc4, 0x75, 0x5e, 0x6e, 0x17, 0xa7, 0xcc, 0x31, + 0x73, 0xe6, 0x60, 0x87, 0xa7, 0xc7, 0x96, 0xb7, 0x03, 0xf5, 0x2e, 0x58, + 0xac, 0x4c, 0x2a, 0x58, 0x92, 0xe2, 0xd8, 0xd7, 0x41, 0x4a, 0xcf, 0xa4, + 0x2d, 0xe9, 0xf9, 0xae, 0x58, 0x87, 0x73, 0x71, 0xda, 0xc4, 0xbd, 0xeb, + 0x16, 0xf7, 0xc1, 0xdf, 0xdc, 0x6e, 0xad, 0xad, 0x37, 0xf5, 0x19, 0x63, + 0x9e, 0xbc, 0x32, 0x63, 0x19, 0x67, 0xe2, 0x6e, 0x51, 0x6d, 0x88, 0x17, + 0x59, 0x49, 0x94, 0x62, 0x0f, 0x6d, 0x7c, 0x2d, 0x6b, 0x12, 0x24, 0xc6, + 0xee, 0x71, 0x98, 0xab, 0x14, 0xca, 0xa3, 0xd1, 0x03, 0x57, 0xcf, 0x52, + 0x79, 0x30, 0xe5, 0x6d, 0x45, 0xc6, 0x66, 0xb0, 0x3b, 0x71, 0x33, 0xb9, + 0x17, 0xcd, 0xfc, 0xe0, 0xcc, 0xb6, 0xe1, 0x67, 0x94, 0x96, 0x36, 0x1d, + 0xaf, 0xf4, 0x99, 0x9c, 0xbd, 0x6b, 0x94, 0x98, 0x3a, 0x61, 0x06, 0xee, + 0x0b, 0xb3, 0x7d, 0x53, 0x3d, 0x3d, 0x98, 0x66, 0x0b, 0x55, 0x35, 0x26, + 0x54, 0xbc, 0x76, 0x77, 0x84, 0xf1, 0x08, 0x90, 0x88, 0x8b, 0x85, 0xc4, + 0x77, 0x42, 0xcf, 0x16, 0x39, 0xe9, 0xf2, 0xb8, 0xad, 0x25, 0x87, 0x23, + 0xfd, 0xca, 0x92, 0x6f, 0xce, 0x5b, 0x04, 0x84, 0x0b, 0xd7, 0x70, 0x2e, + 0xb1, 0x21, 0x16, 0xce, 0xc4, 0x10, 0x73, 0xc8, 0x5c, 0xde, 0x67, 0x35, + 0x62, 0x5a, 0xac, 0x5d, 0x1f, 0x7e, 0x71, 0x26, 0x39, 0x13, 0x08, 0x6f, + 0xfe, 0xd6, 0x13, 0x50, 0xbb, 0xce, 0x33, 0x77, 0x81, 0xd6, 0x32, 0x9b, + 0xf2, 0xd1, 0xea, 0x86, 0xd7, 0x93, 0x70, 0x74, 0xc4, 0x0f, 0xc3, 0x75, + 0x15, 0x11, 0x30, 0xb7, 0xeb, 0xbc, 0x96, 0x4f, 0x70, 0xd7, 0x4b, 0xd6, + 0x7f, 0x67, 0x08, 0x99, 0x26, 0x2d, 0x6b, 0x39, 0xb9, 0xce, 0xd2, 0xa7, + 0xaa, 0x33, 0x48, 0xfb, 0x66, 0x0f, 0x1f, 0x27, 0x99, 0x60, 0x9b, 0x63, + 0x96, 0xc7, 0xc6, 0xa7, 0x1d, 0xb5, 0xa7, 0x5b, 0x98, 0x74, 0xe7, 0xad, + 0xf5, 0x49, 0xbf, 0x98, 0x8f, 0xbc, 0x3c, 0xf3, 0x7d, 0xa1, 0xf5, 0xdf, + 0x8b, 0x25, 0x64, 0x88, 0x05, 0x95, 0x1d, 0x96, 0xc2, 0x5b, 0x88, 0x66, + 0xfb, 0x4f, 0xa8, 0xa8, 0x1e, 0x3d, 0xc2, 0xa9, 0x8a, 0xf9, 0xee, 0xba, + 0xa8, 0x92, 0xb3, 0xc8, 0xa8, 0x9e, 0xc6, 0x08, 0xc1, 0xb6, 0x08, 0x2b, + 0x79, 0xac, 0x0f, 0x2b, 0xa8, 0x2f, 0x51, 0x13, 0x17, 0x1b, 0xb8, 0x99, + 0xf1, 0x05, 0x3c, 0x0c, 0x3b, 0xab, 0xa9, 0x9b, 0x9f, 0x77, 0x49, 0x96, + 0xe7, 0xbe, 0x5e, 0x4b, 0x31, 0x79, 0xb8, 0xf1, 0x0d, 0xc1, 0x78, 0x67, + 0x31, 0x6c, 0xce, 0x21, 0x7b, 0xc3, 0xd4, 0xdc, 0x2a, 0xc8, 0x1a, 0x19, + 0xa8, 0x39, 0xa7, 0xd1, 0x31, 0x61, 0x52, 0xb6, 0xdb, 0xac, 0xe2, 0x33, + 0x8e, 0x39, 0xcd, 0x78, 0x6b, 0x8a, 0xce, 0xc9, 0x21, 0x98, 0x41, 0x65, + 0x26, 0x32, 0x4d, 0x55, 0x19, 0x0b, 0x82, 0xeb, 0x81, 0x7f, 0xdd, 0x33, + 0xde, 0x74, 0x48, 0x81, 0xb3, 0xe4, 0x84, 0x37, 0x90, 0xe6, 0x99, 0x95, + 0x04, 0x8e, 0x24, 0x13, 0x48, 0x5e, 0x0f, 0x63, 0x28, 0x84, 0x0c, 0x39, + 0xac, 0xe3, 0x80, 0xcf, 0x7a, 0x99, 0x92, 0xdf, 0x8d, 0x53, 0xe5, 0x62, + 0x66, 0x26, 0xa2, 0x02, 0x56, 0x62, 0x3e, 0xd5, 0xb3, 0x70, 0x9f, 0x89, + 0x48, 0x82, 0x63, 0x8c, 0xe2, 0x98, 0x9c, 0xee, 0x02, 0x46, 0x62, 0x9a, + 0x77, 0x76, 0xbb, 0x02, 0x75, 0x0d, 0x18, 0xf2, 0x2d, 0xe8, 0x99, 0xac, + 0xc9, 0x76, 0x01, 0x31, 0x99, 0xd9, 0x27, 0x6b, 0x76, 0xc6, 0xf0, 0xdd, + 0x12, 0xcb, 0x30, 0xf7, 0x36, 0xb3, 0x14, 0xc1, 0x35, 0xb8, 0xcb, 0x22, + 0xd3, 0x89, 0x30, 0xcc, 0xc6, 0x24, 0xcd, 0x50, 0x43, 0xee, 0x07, 0xb3, + 0x56, 0xb8, 0x39, 0x87, 0xb6, 0x22, 0x8b, 0x69, 0xf0, 0x5b, 0x13, 0x2f, + 0xd5, 0xf1, 0xa8, 0x8c, 0xad, 0xe2, 0x6d, 0x99, 0xf1, 0x28, 0x13, 0x11, + 0x60, 0xd1, 0x55, 0x25, 0x90, 0x15, 0x11, 0xe1, 0x9b, 0x96, 0xef, 0x17, + 0x53, 0xbe, 0x28, 0x96, 0x0f, 0x8e, 0xa0, 0x8c, 0xb5, 0xda, 0xb9, 0xa3, + 0x38, 0x59, 0xc1, 0x31, 0x37, 0x31, 0x83, 0x73, 0x9f, 0x8f, 0x33, 0x31, + 0x7c, 0x8b, 0xd1, 0x64, 0xb5, 0xac, 0x0b, 0x50, 0x65, 0x31, 0x37, 0x08, + 0x10, 0xf0, 0x4e, 0xab, 0x41, 0x5e, 0x5b, 0x63, 0xa1, 0xfa, 0xf3, 0xc9, + 0x9c, 0xc9, 0x48, 0xc7, 0x9a, 0xc4, 0x64, 0xcd, 0x2c, 0x48, 0x5a, 0xc7, + 0x29, 0x28, 0x71, 0xd3, 0x9a, 0x82, 0x28, 0x67, 0xea, 0x89, 0xa8, 0xe3, + 0x62, 0x8f, 0xb0, 0x94, 0x95, 0x9d, 0x02, 0x42, 0x01, 0x38, 0x90, 0x61, + 0x5f, 0x5a, 0xee, 0xaa, 0xca, 0x12, 0x55, 0x22, 0xdf, 0x2b, 0x48, 0xc3, + 0x64, 0x12, 0xb7, 0xe5, 0xfe, 0xf6, 0x76, 0x4e, 0x34, 0x9e, 0x09, 0xc0, + 0x47, 0x96, 0x2e, 0x30, 0x14, 0xc8, 0xae, 0x22, 0xa4, 0x00, 0xa0, 0x62, + 0x9e, 0x70, 0x28, 0x69, 0x01, 0x01, 0x9d, 0x0a, 0x94, 0x28, 0x25, 0xa5, + 0x8e, 0x59, 0x8d, 0xe4, 0x11, 0x26, 0x25, 0x42, 0xfa, 0x81, 0x2a, 0xb9, + 0x29, 0x21, 0x38, 0xa0, 0x9d, 0x66, 0xd3, 0x58, 0xa2, 0x19, 0x22, 0xf9, + 0x71, 0x78, 0x9e, 0x95, 0x32, 0x49, 0x3b, 0xc3, 0xe0, 0x9a, 0x16, 0x78, + 0x4c, 0x60, 0x56, 0xc9, 0x1e, 0xd8, 0x72, 0xcc, 0xc4, 0x67, 0x75, 0x44, + 0x5a, 0x93, 0x32, 0xc5, 0x8e, 0x30, 0x2e, 0x25, 0x75, 0x6c, 0xf4, 0x30, + 0xe1, 0x33, 0x77, 0x0b, 0x13, 0x10, 0x34, 0x15, 0x31, 0xf3, 0x0c, 0xe0, + 0x26, 0xa2, 0x21, 0x9d, 0x42, 0x90, 0x5c, 0x6f, 0x26, 0x22, 0x3d, 0x70, + 0x1b, 0x9b, 0x4b, 0x7a, 0x88, 0x8a, 0x9f, 0x46, 0x2e, 0x88, 0xdf, 0x37, + 0x87, 0x2e, 0x1d, 0xe7, 0xcb, 0x64, 0xc9, 0x32, 0x16, 0x47, 0x25, 0x23, + 0x61, 0x31, 0x9f, 0x04, 0xce, 0x2d, 0x09, 0xbc, 0x6a, 0xce, 0x5c, 0x6c, + 0x83, 0x06, 0x98, 0x98, 0x92, 0xe3, 0x18, 0x16, 0xe9, 0x6f, 0x90, 0xb7, + 0x0d, 0xe9, 0xd1, 0xdc, 0xd6, 0x1c, 0x78, 0x88, 0x84, 0xa0, 0x99, 0x69, + 0x68, 0xa4, 0x14, 0xf1, 0xd2, 0x88, 0x86, 0x6c, 0xa6, 0x89, 0x49, 0x45, + 0x20, 0x8a, 0xf9, 0x9d, 0xa3, 0x39, 0xa9, 0x60, 0x8e, 0x0d, 0xe1, 0xe2, + 0x21, 0x8e, 0x70, 0x02, 0xb4, 0x92, 0xae, 0x08, 0x82, 0xa6, 0x11, 0x83, + 0x22, 0x20, 0xb0, 0xc7, 0x2e, 0x10, 0x08, 0xf3, 0x22, 0x3c, 0x67, 0xc8, + 0x6b, 0xf4, 0x2b, 0xfd, 0xfb, 0x41, 0x11, 0x04, 0x44, 0x44, 0x91, 0x1a, + 0x44, 0x69, 0x13, 0x27, 0x1c, 0x57, 0x1d, 0x3b, 0x58, 0x86, 0xae, 0xbb, + 0x86, 0x43, 0x67, 0x63, 0xb6, 0xeb, 0x39, 0x5b, 0xca, 0xc8, 0x84, 0x93, + 0x08, 0x8f, 0x05, 0x11, 0x8a, 0x54, 0x35, 0x2c, 0x32, 0x71, 0xf2, 0x0d, + 0xd2, 0x61, 0xc0, 0x22, 0x66, 0xea, 0xdf, 0x30, 0xf2, 0x64, 0x32, 0x78, + 0x53, 0x77, 0x44, 0xfe, 0x9b, 0x8e, 0x6e, 0xe8, 0x4c, 0x7e, 0xf2, 0xff, + 0x00, 0x9c, 0x9d, 0xf2, 0x30, 0x61, 0x88, 0x6d, 0x1c, 0xee, 0x32, 0x9e, + 0xe4, 0xf1, 0x1c, 0x62, 0x19, 0x07, 0x18, 0xba, 0x27, 0xc3, 0x06, 0x63, + 0xeb, 0x86, 0xbe, 0x96, 0xcf, 0xb9, 0xe1, 0x29, 0xd0, 0xca, 0x4f, 0xd3, + 0x9a, 0x58, 0x99, 0xe3, 0xf4, 0x8d, 0x57, 0xed, 0xc7, 0xcc, 0xb9, 0x4e, + 0x32, 0x04, 0x0b, 0x1b, 0xfe, 0xa2, 0x3a, 0x65, 0x6a, 0x99, 0x9e, 0x5c, + 0x0e, 0xeb, 0x44, 0x63, 0x37, 0x97, 0x7d, 0xe2, 0xb5, 0xc1, 0xa8, 0xed, + 0x91, 0x26, 0xe8, 0x91, 0xee, 0x28, 0xff, 0x00, 0xd8, 0x4c, 0x72, 0x43, + 0x2b, 0x3b, 0xd0, 0x34, 0xdd, 0x4f, 0x05, 0x68, 0x84, 0x38, 0x90, 0x26, + 0xe5, 0x4b, 0x59, 0x4c, 0xc8, 0x72, 0x41, 0xf7, 0xf9, 0x66, 0xc7, 0x95, + 0x18, 0x03, 0x81, 0xaa, 0x87, 0x08, 0xd2, 0x36, 0x07, 0xb0, 0x6f, 0x0c, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x40, 0x05, 0x00, 0x60, 0xff, + 0x00, 0xfc, 0x29, 0xfc, 0xc5, 0xc7, 0x65, 0x75, 0x2d, 0xc9, 0x59, 0xb9, + 0x9e, 0x28, 0x42, 0x83, 0x91, 0x8f, 0xeb, 0xff, 0x00, 0xce, 0x9d, 0x97, + 0x77, 0xf0, 0x7e, 0x15, 0xff, 0x00, 0xe9, 0x03, 0x3f, 0xae, 0x79, 0xbb, + 0xfa, 0x1f, 0x5c, 0xfe, 0xe5, 0xa8, 0xfc, 0x2b, 0xd5, 0x7f, 0xf9, 0x90, + 0x09, 0x83, 0x9b, 0x62, 0xd7, 0xb7, 0x6f, 0xff, 0x00, 0x32, 0x01, 0x83, + 0xf4, 0x7c, 0x29, 0x6a, 0xbd, 0xaf, 0xc2, 0x0d, 0x99, 0x67, 0x29, 0x97, + 0xf4, 0x85, 0x9e, 0x0e, 0xbf, 0xfe, 0x17, 0xff, 0xd9 +}; +unsigned int background_T3T1_jpg_len = 50577; diff --git a/core/embed/models/T3T1/background_T3T1.jpg b/core/embed/models/T3T1/background_T3T1.jpg new file mode 100644 index 0000000000..a8f06e4686 Binary files /dev/null and b/core/embed/models/T3T1/background_T3T1.jpg differ diff --git a/core/embed/models/T3T1/boards/t3t1-unix.h b/core/embed/models/T3T1/boards/t3t1-unix.h new file mode 100644 index 0000000000..26be4fec37 --- /dev/null +++ b/core/embed/models/T3T1/boards/t3t1-unix.h @@ -0,0 +1,27 @@ +#ifndef BOARDS_T3T1_UNIX_H +#define BOARDS_T3T1_UNIX_H + +#define USE_TOUCH 1 +#define USE_SD_CARD 1 +#define USE_SBU 1 +#define USE_RGB_COLORS 1 +#define USE_BACKLIGHT 1 +#define USE_OPTIGA 1 + +#define MAX_DISPLAY_RESX 240 +#define MAX_DISPLAY_RESY 240 +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define TREZOR_FONT_BPP 4 + +#define WINDOW_WIDTH 400 +#define WINDOW_HEIGHT 600 +#define TOUCH_OFFSET_X 80 +#define TOUCH_OFFSET_Y 102 + +#define ORIENTATION_NSEW 1 + +#define BACKGROUND_FILE "T3T1/background_T3T1.h" +#define BACKGROUND_NAME background_T3T1_jpg + +#endif // BOARDS_T3T1_UNIX_H diff --git a/core/embed/trezorhal/boards/trezor_t3t1_revE.h b/core/embed/models/T3T1/boards/trezor_t3t1_revE.h similarity index 93% rename from core/embed/trezorhal/boards/trezor_t3t1_revE.h rename to core/embed/models/T3T1/boards/trezor_t3t1_revE.h index 95e11f796f..591ff37b52 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_revE.h +++ b/core/embed/models/T3T1/boards/trezor_t3t1_revE.h @@ -1,9 +1,6 @@ #ifndef _TREZOR_T3T1_H #define _TREZOR_T3T1_H -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define VDD_3V3 1 #define USE_SD_CARD 1 @@ -16,8 +13,11 @@ #define USE_BACKLIGHT 1 #define USE_HASH_PROCESSOR 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 @@ -26,10 +26,6 @@ #define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD #define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_12 -#define DISPLAY_PANEL_INIT_SEQ lx154a2422_init_seq -#define DISPLAY_PANEL_ROTATE lx154a2422_rotate -#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords - #define BACKLIGHT_PWM_FREQ 12500 #define BACKLIGHT_PWM_TIM TIM17 #define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM17_CLK_ENABLE @@ -81,6 +77,7 @@ #define I2C_INSTANCE_2_RESET_REG &RCC->APB3RSTR #define I2C_INSTANCE_2_RESET_BIT RCC_APB3RSTR_I2C3RST +#define TOUCH_PANEL_LX154A2422CPT23 1 #define TOUCH_SENSITIVITY 0x40 #define TOUCH_I2C_INSTANCE 0 #define TOUCH_RST_PORT GPIOC diff --git a/core/embed/trezorhal/boards/trezor_t3t1_v4.h b/core/embed/models/T3T1/boards/trezor_t3t1_v4.h similarity index 92% rename from core/embed/trezorhal/boards/trezor_t3t1_v4.h rename to core/embed/models/T3T1/boards/trezor_t3t1_v4.h index a43dee3789..bf2c0a00d8 100644 --- a/core/embed/trezorhal/boards/trezor_t3t1_v4.h +++ b/core/embed/models/T3T1/boards/trezor_t3t1_v4.h @@ -1,9 +1,6 @@ #ifndef _TREZOR_T3T1_H #define _TREZOR_T3T1_H -#define DISPLAY_RESX 240 -#define DISPLAY_RESY 240 - #define VDD_3V3 1 #define HSE_16MHZ 1 @@ -17,8 +14,11 @@ #define USE_BACKLIGHT 1 #define USE_HASH_PROCESSOR 1 -#include "displays/panels/lx154a2422.h" -#include "displays/st7789v.h" +#define DISPLAY_RESX 240 +#define DISPLAY_RESY 240 +#define DISPLAY_LEGACY_HEADER "displays/st7789v.h" +#define DISPLAY_COLOR_MODE DMA2D_OUTPUT_RGB565 + #define DISPLAY_IDENTIFY 1 #define DISPLAY_TE_PORT GPIOD #define DISPLAY_TE_PIN GPIO_PIN_12 @@ -27,10 +27,6 @@ #define DISPLAY_TE_INTERRUPT_GPIOSEL EXTI_GPIOD #define DISPLAY_TE_INTERRUPT_EXTI_LINE EXTI_LINE_12 -#define DISPLAY_PANEL_INIT_SEQ lx154a2422_init_seq -#define DISPLAY_PANEL_ROTATE lx154a2422_rotate -#define TRANSFORM_TOUCH_COORDS lx154a2422_transform_touch_coords - #define BACKLIGHT_PWM_FREQ 12500 #define BACKLIGHT_PWM_TIM TIM8 #define BACKLIGHT_PWM_TIM_CLK_EN __HAL_RCC_TIM8_CLK_ENABLE diff --git a/core/embed/firmware/bootloaders/bootloader_T3T1.bin b/core/embed/models/T3T1/bootloaders/bootloader_T3T1.bin similarity index 69% rename from core/embed/firmware/bootloaders/bootloader_T3T1.bin rename to core/embed/models/T3T1/bootloaders/bootloader_T3T1.bin index 75d2060f63..79eed95909 100644 Binary files a/core/embed/firmware/bootloaders/bootloader_T3T1.bin and b/core/embed/models/T3T1/bootloaders/bootloader_T3T1.bin differ diff --git a/core/embed/models/T3T1/bootloaders/bootloader_T3T1_qa.bin b/core/embed/models/T3T1/bootloaders/bootloader_T3T1_qa.bin new file mode 100755 index 0000000000..a40c63494a Binary files /dev/null and b/core/embed/models/T3T1/bootloaders/bootloader_T3T1_qa.bin differ diff --git a/core/embed/models/T3T1/bootloaders/bootloader_hashes.h b/core/embed/models/T3T1/bootloaders/bootloader_hashes.h new file mode 100644 index 0000000000..d4dcbffc2a --- /dev/null +++ b/core/embed/models/T3T1/bootloaders/bootloader_hashes.h @@ -0,0 +1,17 @@ +#ifndef BOOTLOADER_HASHES_H +#define BOOTLOADER_HASHES_H + +// Auto-generated file, do not edit. + +// clang-format off +// bootloader_T3T1.bin version 2.1.6.0 +#define BOOTLOADER_T3T1_00 {0x4a, 0x07, 0x5c, 0x74, 0x0f, 0x9a, 0x84, 0x61, 0xaf, 0x10, 0x34, 0x9c, 0x24, 0x3d, 0x79, 0x5b, 0xc6, 0x12, 0x5e, 0xec, 0x51, 0xb3, 0x91, 0x4b, 0x65, 0xf9, 0x79, 0x17, 0x98, 0xc2, 0x4f, 0xcb} +#define BOOTLOADER_T3T1_FF {0xd8, 0xee, 0x0d, 0xd8, 0x87, 0x0b, 0xf4, 0x38, 0x73, 0x52, 0x83, 0x5e, 0xa9, 0xef, 0x3e, 0x5a, 0x3e, 0x59, 0xc2, 0x12, 0x5b, 0x24, 0xc9, 0x2d, 0xd4, 0xc5, 0xf5, 0x57, 0x15, 0x8a, 0x34, 0x78} + +// bootloader_T3T1_qa.bin version 2.1.6.0 +#define BOOTLOADER_T3T1_QA_00 {0x53, 0x5f, 0xf9, 0xa8, 0x21, 0x7d, 0xb5, 0x39, 0xe4, 0xfa, 0xf8, 0x3d, 0x0d, 0xe6, 0xf3, 0x65, 0x21, 0x30, 0x46, 0x9e, 0x40, 0x85, 0xd4, 0xd8, 0x49, 0x00, 0xb0, 0xb5, 0x58, 0x39, 0xe3, 0xd4} +#define BOOTLOADER_T3T1_QA_FF {0x1e, 0x03, 0x50, 0x25, 0xa1, 0xc7, 0x20, 0xe2, 0x04, 0x62, 0x24, 0xa1, 0x31, 0xc2, 0xf5, 0x7b, 0x35, 0xe9, 0x22, 0x42, 0x36, 0x2d, 0xab, 0xcc, 0xb6, 0x3b, 0xfe, 0x88, 0x53, 0x2f, 0x49, 0xa7} + +// clang-format on + +#endif diff --git a/core/embed/models/model_T3T1.h b/core/embed/models/T3T1/model_T3T1.h similarity index 93% rename from core/embed/models/model_T3T1.h rename to core/embed/models/T3T1/model_T3T1.h index 85717f7f22..cbada112e4 100644 --- a/core/embed/models/model_T3T1.h +++ b/core/embed/models/T3T1/model_T3T1.h @@ -1,6 +1,8 @@ #ifndef MODELS_MODEL_T3T1_H_ #define MODELS_MODEL_T3T1_H_ +#include "bootloaders/bootloader_hashes.h" + #include "sizedefs.h" #define MODEL_NAME "Safe 5" @@ -8,6 +10,8 @@ #define MODEL_INTERNAL_NAME "T3T1" #define MODEL_INTERNAL_NAME_TOKEN T3T1 #define MODEL_INTERNAL_NAME_QSTR MP_QSTR_T3T1 +#define MODEL_USB_MANUFACTURER "Trezor Company" +#define MODEL_USB_PRODUCT MODEL_FULL_NAME #define MODEL_BOARDLOADER_KEYS \ (const uint8_t *)"\x76\xaf\x42\x6e\x61\x40\x6b\xad\x7c\x07\x7b\x40\x9c\x66\xfd\xe3\x9f\xb8\x17\x91\x93\x13\xae\x1e\x4c\x02\x53\x5c\x80\xbe\xed\x96", \ @@ -22,6 +26,7 @@ #define IMAGE_CHUNK_SIZE (128 * 1024) #define IMAGE_HASH_SHA256 #define BOARD_CAPABILITIES_ADDR 0x0C00FF00 +#define CODE_ALIGNMENT 0x200 // SHARED WITH MAKEFILE #define FLASH_START 0x0C000000 diff --git a/core/embed/models/T3T1/model_T3T1_layout.c b/core/embed/models/T3T1/model_T3T1_layout.c new file mode 100644 index 0000000000..3baae222ed --- /dev/null +++ b/core/embed/models/T3T1/model_T3T1_layout.c @@ -0,0 +1,96 @@ +#include "flash.h" +#include "model.h" + +const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = { + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = STORAGE_1_SECTOR_START, + .num_sectors = + STORAGE_1_SECTOR_END - STORAGE_1_SECTOR_START + 1, + }, + }, + { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = STORAGE_2_SECTOR_START, + .num_sectors = + STORAGE_2_SECTOR_END - STORAGE_2_SECTOR_START + 1, + }, + }, +}; + +const flash_area_t BOARDLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = BOARDLOADER_SECTOR_START, + .num_sectors = + BOARDLOADER_SECTOR_END - BOARDLOADER_SECTOR_START + 1, + }, +}; + +const flash_area_t BOOTLOADER_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = BOOTLOADER_SECTOR_START, + .num_sectors = BOOTLOADER_SECTOR_END - BOOTLOADER_SECTOR_START + 1, + }, +}; + +const flash_area_t FIRMWARE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = FIRMWARE_SECTOR_START, + .num_sectors = FIRMWARE_SECTOR_END - FIRMWARE_SECTOR_START + 1, + }, +}; + +const flash_area_t SECRET_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 0, + .num_sectors = 2, + }, +}; + +const flash_area_t BHK_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 1, + .num_sectors = 1, + }, +}; + +const flash_area_t TRANSLATIONS_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = 248, + .num_sectors = 8, + }, +}; + +const flash_area_t WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = STORAGE_1_SECTOR_START, + .num_sectors = 232, + }, +}; + +const flash_area_t ALL_WIPE_AREA = { + .num_subareas = 1, + .subarea[0] = + { + .first_sector = BOOTLOADER_SECTOR_START, + .num_sectors = 248, + }, +}; diff --git a/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.json b/core/embed/models/T3T1/vendorheader/vendor_dev_DO_NOT_SIGN.json similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.json rename to core/embed/models/T3T1/vendorheader/vendor_dev_DO_NOT_SIGN.json diff --git a/core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.toif b/core/embed/models/T3T1/vendorheader/vendor_dev_DO_NOT_SIGN.toif similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_dev_DO_NOT_SIGN.toif rename to core/embed/models/T3T1/vendorheader/vendor_dev_DO_NOT_SIGN.toif diff --git a/core/embed/vendorheader/T3T1/vendor_prodtest.json b/core/embed/models/T3T1/vendorheader/vendor_prodtest.json similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_prodtest.json rename to core/embed/models/T3T1/vendorheader/vendor_prodtest.json diff --git a/core/embed/vendorheader/T3T1/vendor_prodtest.toif b/core/embed/models/T3T1/vendorheader/vendor_prodtest.toif similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_prodtest.toif rename to core/embed/models/T3T1/vendorheader/vendor_prodtest.toif diff --git a/core/embed/vendorheader/T3T1/vendor_trezor.json b/core/embed/models/T3T1/vendorheader/vendor_trezor.json similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_trezor.json rename to core/embed/models/T3T1/vendorheader/vendor_trezor.json diff --git a/core/embed/vendorheader/T3T1/vendor_trezor.toif b/core/embed/models/T3T1/vendorheader/vendor_trezor.toif similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_trezor.toif rename to core/embed/models/T3T1/vendorheader/vendor_trezor.toif diff --git a/core/embed/vendorheader/T3T1/vendor_trezor_btconly.json b/core/embed/models/T3T1/vendorheader/vendor_trezor_btconly.json similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_trezor_btconly.json rename to core/embed/models/T3T1/vendorheader/vendor_trezor_btconly.json diff --git a/core/embed/vendorheader/T3T1/vendor_trezor_btconly.toif b/core/embed/models/T3T1/vendorheader/vendor_trezor_btconly.toif similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_trezor_btconly.toif rename to core/embed/models/T3T1/vendorheader/vendor_trezor_btconly.toif diff --git a/core/embed/vendorheader/T3T1/vendor_unsafe.json b/core/embed/models/T3T1/vendorheader/vendor_unsafe.json similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_unsafe.json rename to core/embed/models/T3T1/vendorheader/vendor_unsafe.json diff --git a/core/embed/vendorheader/T3T1/vendor_unsafe.toif b/core/embed/models/T3T1/vendorheader/vendor_unsafe.toif similarity index 100% rename from core/embed/vendorheader/T3T1/vendor_unsafe.toif rename to core/embed/models/T3T1/vendorheader/vendor_unsafe.toif diff --git a/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin b/core/embed/models/T3T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_signed_dev.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin b/core/embed/models/T3T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_dev_DO_NOT_SIGN_unsigned.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_dev_DO_NOT_SIGN_unsigned.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_prodtest_signed_prod.bin b/core/embed/models/T3T1/vendorheader/vendorheader_prodtest_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_prodtest_signed_prod.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_prodtest_signed_prod.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_prodtest_unsigned.bin b/core/embed/models/T3T1/vendorheader/vendorheader_prodtest_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_prodtest_unsigned.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_prodtest_unsigned.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_trezor_btconly_signed_prod.bin b/core/embed/models/T3T1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_trezor_btconly_signed_prod.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_trezor_btconly_signed_prod.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_trezor_btconly_unsigned.bin b/core/embed/models/T3T1/vendorheader/vendorheader_trezor_btconly_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_trezor_btconly_unsigned.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_trezor_btconly_unsigned.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_trezor_signed_prod.bin b/core/embed/models/T3T1/vendorheader/vendorheader_trezor_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_trezor_signed_prod.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_trezor_signed_prod.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_trezor_unsigned.bin b/core/embed/models/T3T1/vendorheader/vendorheader_trezor_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_trezor_unsigned.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_trezor_unsigned.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_dev.bin b/core/embed/models/T3T1/vendorheader/vendorheader_unsafe_signed_dev.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_dev.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_unsafe_signed_dev.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_prod.bin b/core/embed/models/T3T1/vendorheader/vendorheader_unsafe_signed_prod.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_unsafe_signed_prod.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_unsafe_signed_prod.bin diff --git a/core/embed/vendorheader/T3T1/vendorheader_unsafe_unsigned.bin b/core/embed/models/T3T1/vendorheader/vendorheader_unsafe_unsigned.bin similarity index 100% rename from core/embed/vendorheader/T3T1/vendorheader_unsafe_unsigned.bin rename to core/embed/models/T3T1/vendorheader/vendorheader_unsafe_unsigned.bin diff --git a/core/embed/models/T3T1/versions.h b/core/embed/models/T3T1/versions.h new file mode 100644 index 0000000000..546ca6a16b --- /dev/null +++ b/core/embed/models/T3T1/versions.h @@ -0,0 +1,3 @@ + +#define BOOTLOADER_MONOTONIC_VERSION 2 +#define FIRMWARE_MONOTONIC_VERSION 2 diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h index e95f868bf0..318bf5abd4 100644 --- a/core/embed/models/layout_common.h +++ b/core/embed/models/layout_common.h @@ -9,6 +9,7 @@ #define FLASH_OTP_BLOCK_VENDOR_HEADER_LOCK 2 #define FLASH_OTP_BLOCK_RANDOMNESS 3 #define FLASH_OTP_BLOCK_DEVICE_VARIANT 4 +#define FLASH_OTP_BLOCK_FIRMWARE_VERSION 5 #define STORAGE_AREAS_COUNT (2) diff --git a/core/embed/models/model.h b/core/embed/models/model.h index 1b98b8a81c..fa797575b4 100644 --- a/core/embed/models/model.h +++ b/core/embed/models/model.h @@ -4,17 +4,19 @@ #include "layout_common.h" #if defined TREZOR_MODEL_1 -#include "model_T1B1.h" +#include "T1B1/model_T1B1.h" #elif defined TREZOR_MODEL_T -#include "model_T2T1.h" +#include "T2T1/model_T2T1.h" #elif defined TREZOR_MODEL_R -#include "model_T2B1.h" +#include "T2B1/model_T2B1.h" #elif defined TREZOR_MODEL_T3T1 -#include "model_T3T1.h" +#include "T3T1/model_T3T1.h" +#elif defined TREZOR_MODEL_T3B1 +#include "T3B1/model_T3B1.h" #elif defined TREZOR_MODEL_DISC1 -#include "model_D001.h" +#include "D001/model_D001.h" #elif defined TREZOR_MODEL_DISC2 -#include "model_D002.h" +#include "D002/model_D002.h" #else #error Unknown Trezor model #endif diff --git a/core/embed/models/model_D001_layout.c b/core/embed/models/model_D001_layout.c deleted file mode 120000 index e68955d8d8..0000000000 --- a/core/embed/models/model_D001_layout.c +++ /dev/null @@ -1 +0,0 @@ -model_T2T1_layout.c \ No newline at end of file diff --git a/core/embed/models/model_version.h b/core/embed/models/model_version.h new file mode 100644 index 0000000000..71b5b65f7b --- /dev/null +++ b/core/embed/models/model_version.h @@ -0,0 +1,22 @@ +#ifndef MODELS_MODEL_H_ +#define MODELS_MODEL_H_ + +#if defined TREZOR_MODEL_1 +#include "T1B1/versions.h" +#elif defined TREZOR_MODEL_T +#include "T2T1/versions.h" +#elif defined TREZOR_MODEL_R +#include "T2B1/versions.h" +#elif defined TREZOR_MODEL_T3T1 +#include "T3T1/versions.h" +#elif defined TREZOR_MODEL_T3B1 +#include "T3B1/versions.h" +#elif defined TREZOR_MODEL_DISC1 +#include "D001/versions.h" +#elif defined TREZOR_MODEL_DISC2 +#include "D002/versions.h" +#else +#error Unknown Trezor model +#endif + +#endif diff --git a/core/embed/prodtest/.changelog.d/+version.added b/core/embed/prodtest/.changelog.d/+version.added deleted file mode 100644 index f3d8542769..0000000000 --- a/core/embed/prodtest/.changelog.d/+version.added +++ /dev/null @@ -1 +0,0 @@ -Added FIRMWARE VERSION command. diff --git a/core/embed/prodtest/CHANGELOG.md b/core/embed/prodtest/CHANGELOG.md index 1582b496ad..b294095379 100644 --- a/core/embed/prodtest/CHANGELOG.md +++ b/core/embed/prodtest/CHANGELOG.md @@ -1,4 +1,43 @@ +## 0.2.9 [7th September 2024] + +### Added +- Added commands to read bootloader and boardloader versions [#3752] +- Added TOUCH_CUSTOM and TOUCH_IDLE commands [#4064] + +### Changed +- [T3B1] Changed welcome screen to show full white display [#4140] + +## 0.2.8 [19th July 2024] + +### Added +- [T3B1] Added support for T3B1. + +### Fixed +- Fix TOUCH VERSION command [#3900] + + +## 0.2.7 [10th June 2024] + +### Added +- Added REBOOT command [#3932] + +### Fixed +- Fix TOUCH_VERSION command [#3932] + + +## 0.2.6 [6th May 2024] + +### Added +- Added FIRMWARE VERSION command. + +### Changed +- [T3T1] Changed USB manufacturer string to "Trezor Company" and product string to "Trezor Safe 5" in the USB descriptor strings. [#3770] + +### Fixed +- [T3T1] Fixed `WIPE` command on STM32U5. [#3769] + + ## 0.2.5 [16th April 2024] ### Added @@ -29,6 +68,12 @@ ### Changed - [T2B1] Start with all-white screen instead of border. [#3325] - [#3325]: https://github.com/trezor/trezor-firmware/pull/3325 [#3370]: https://github.com/trezor/trezor-firmware/pull/3370 +[#3752]: https://github.com/trezor/trezor-firmware/pull/3752 +[#3769]: https://github.com/trezor/trezor-firmware/pull/3769 +[#3770]: https://github.com/trezor/trezor-firmware/pull/3770 +[#3900]: https://github.com/trezor/trezor-firmware/pull/3900 +[#3932]: https://github.com/trezor/trezor-firmware/pull/3932 +[#4064]: https://github.com/trezor/trezor-firmware/pull/4064 +[#4140]: https://github.com/trezor/trezor-firmware/pull/4140 diff --git a/core/embed/prodtest/README.md b/core/embed/prodtest/README.md index 1ff4dd4339..64d6eb4ced 100644 --- a/core/embed/prodtest/README.md +++ b/core/embed/prodtest/README.md @@ -88,7 +88,7 @@ OK ``` ### TOUCH -The `TOUCH` command test the functionality of the display's touch screen. +The `TOUCH` command tests the functionality of the display's touch screen. It draws a filled rectangle in one of the four display quadrants and waits for user interaction. The command requires two input parameters: @@ -106,6 +106,48 @@ TOUCH 09 OK 50 90 ``` + +### TOUCH_CUSTOM +The `TOUCH_CUSTOM` command tests the functionality of the display's touch screen. +It draws a filled rectangle on custom coordinates and waits for user interaction. + +The command requires five input parameters: + +* X position of the top-left corner of the rectangle +* Y position of the top-left corner of the rectangle +* Width of the rectangle +* Height of the rectangle +* The timeout in seconds + +If the display is not touched within the specified timeout, the command will return an `ERROR TIMEOUT`. + +The device report touch events, coordinates and timestamps (in ms), correctness of the touch point is not checked and is left to the test equipment. + +The test ends with first lift-up event. + +Example (to draw a 100x100 rectangle in the top-left (10,10) position and wait for 15 seconds for touch input): +``` +TOUCH_CUSTOM 10 10 100 100 15 +TOUCH D 69 35 357300 +TOUCH U 69 35 357328 +OK +``` + +### TOUCH_IDLE +The `TOUCH_IDLE` command tests the functionality of the display's touch screen. +It waits for a specific time period without any touch input. + +The command requires one input parameter: +* The timeout in seconds + +If a touch activity is detected within the specified timeout, the command will return an `ERROR TOUCH DETECTED`. + +Example - wait ten seconds for no touch input: +``` +TOUCH_IDLE 10 +OK +``` + ### SENS The `SENS` command is used to evaluating the touch screen sensitivity. It draws a filled box around the touch coordinates. @@ -240,6 +282,26 @@ FIRMWARE VERSION OK 0.2.6 ``` +### BOOTLOADER VERSION +Returns the version of the bootlaoder. +The command returns `OK` followed by the version in the format `..`. + +Example: +``` +BOOTLOADER_VERSION +OK 2.1.7 +``` + +### BOARDLOADER VERSION +Returns the version of the boardloader. +The command returns `OK` followed by the version in the format `..`. + +Example: +``` +FIRMWARE VERSION +OK 0.2.6 +``` + ### WIPE This command invalidates the current firmware in the flash memory by erasing its beginning, including metadata. After performing this operation, it displays the text "WIPED" on the screen and returns the response OK. @@ -250,6 +312,13 @@ WIPE OK ``` +### REBOOT +This command initiates device reboot. No response, as the device reboots immediately after receiving the command. +Example: +``` +REBOOT +``` + ### OPTIGAID READ Returns the coprocessor UID of the Optiga chip as a 27 byte hexadecimal string. diff --git a/core/embed/prodtest/header.S b/core/embed/prodtest/header.S index ce84552baa..2c101aa43c 100644 --- a/core/embed/prodtest/header.S +++ b/core/embed/prodtest/header.S @@ -26,7 +26,7 @@ g_header: .byte FIX_VERSION_BUILD // fix_vbuild .word HW_MODEL // type of the designated hardware .byte HW_REVISION // revision of the designated hardware - .byte VERSION_MONOTONIC // monotonic version of the binary + .byte FIRMWARE_MONOTONIC_VERSION // monotonic version of the binary . = . + 2 // reserved . = . + 512 // hash1 ... hash16 . = . + 415 // reserved diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 986e7c850f..2d35986e05 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -17,15 +17,18 @@ * along with this program. If not, see . */ +#include #include #include #include #include STM32_HAL_H +#include "board_capabilities.h" #include "button.h" #include "common.h" #include "display.h" +#include "display_draw.h" #include "display_utils.h" #include "fault_handlers.h" #include "flash.h" @@ -78,7 +81,7 @@ static secbool startswith(const char *s, const char *prefix) { static void vcp_intr(void) { display_clear(); - ensure(secfalse, "vcp_intr"); + error_shutdown("vcp_intr"); } static char vcp_getchar(void) { @@ -123,8 +126,8 @@ static void usb_init_all(void) { .vendor_id = 0x1209, .product_id = 0x53C1, .release_num = 0x0400, - .manufacturer = "SatoshiLabs", - .product = "TREZOR", + .manufacturer = MODEL_USB_MANUFACTURER, + .product = MODEL_USB_PRODUCT, .serial_number = "000000000000", .interface = "TREZOR Interface", .usb21_enabled = secfalse, @@ -147,16 +150,40 @@ static void usb_init_all(void) { .rx_intr_byte = 3, // Ctrl-C .iface_num = VCP_IFACE, .data_iface_num = 0x01, - .ep_cmd = 0x82, - .ep_in = 0x81, + .ep_cmd = 0x02, + .ep_in = 0x01, .ep_out = 0x01, .polling_interval = 10, .max_packet_len = VCP_PACKET_LEN, }; - usb_init(&dev_info); + ensure(usb_init(&dev_info), NULL); ensure(usb_vcp_add(&vcp_info), "usb_vcp_add"); - usb_start(); + ensure(usb_start(), NULL); +} + +void extract_params(const char *str, int *numbers, int *count, int max_count) { + int i = 0; + int num_index = 0; + int len = strlen(str); + char buffer[20]; // buffer to hold the current number string + + while (i < len && num_index < max_count) { + if (isdigit((int)str[i])) { + int buffer_index = 0; + // Extract the number + while (isdigit((int)str[i]) && i < len) { + buffer[buffer_index++] = str[i++]; + } + buffer[buffer_index] = '\0'; // null-terminate the string + + // Convert the extracted string to an integer + numbers[num_index++] = atoi(buffer); + } else { + i++; + } + } + *count = num_index; } static void draw_border(int width, int padding) { @@ -168,7 +195,7 @@ static void draw_border(int width, int padding) { } static void draw_welcome_screen(void) { -#if TREZOR_MODEL_R +#if defined TREZOR_MODEL_R || defined TREZOR_MODEL_T3B1 display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, 0xFFFF); display_refresh(); #else @@ -311,15 +338,15 @@ static secbool touch_click_timeout(uint32_t *touch, uint32_t timeout_ms) { uint32_t deadline = HAL_GetTick() + timeout_ms; uint32_t r = 0; - while (touch_read()) + while (touch_get_event()) ; - while ((touch_read() & TOUCH_START) == 0) { + while ((touch_get_event() & TOUCH_START) == 0) { if (HAL_GetTick() > deadline) return secfalse; } - while (((r = touch_read()) & TOUCH_END) == 0) { + while (((r = touch_get_event()) & TOUCH_END) == 0) { if (HAL_GetTick() > deadline) return secfalse; } - while (touch_read()) + while (touch_get_event()) ; *touch = r; @@ -330,24 +357,27 @@ static void test_touch(const char *args) { int column = args[0] - '0'; int timeout = args[1] - '0'; + const int width = DISPLAY_RESX / 2; + const int height = DISPLAY_RESY / 2; + display_clear(); switch (column) { case 1: - display_bar(0, 0, 120, 120, 0xFFFF); + display_bar(0, 0, width, height, 0xFFFF); break; case 2: - display_bar(120, 0, 120, 120, 0xFFFF); + display_bar(width, 0, width, height, 0xFFFF); break; case 3: - display_bar(120, 120, 120, 120, 0xFFFF); + display_bar(width, height, width, height, 0xFFFF); break; default: - display_bar(0, 120, 120, 120, 0xFFFF); + display_bar(0, height, width, height, 0xFFFF); break; } display_refresh(); - touch_power_on(); + touch_init(); uint32_t evt = 0; if (touch_click_timeout(&evt, timeout * 1000)) { @@ -360,20 +390,122 @@ static void test_touch(const char *args) { display_clear(); display_refresh(); - touch_power_off(); + touch_deinit(); +} + +static void test_touch_custom(const char *args) { + static const int expected_params = 5; + + int params[expected_params]; + int num_params = 0; + + extract_params(args, params, &num_params, expected_params); + + if (num_params != expected_params) { + vcp_println("ERROR PARAM"); + return; + } + +#undef NUM_PARAMS + + int x = params[0]; + int y = params[1]; + int width = params[2]; + int height = params[3]; + int timeout = params[4]; + + uint32_t ticks_start = hal_ticks_ms(); + + display_clear(); + display_bar(x, y, width, height, 0xFFFF); + display_refresh(); + + touch_init(); + + while (true) { + if (hal_ticks_ms() - ticks_start > timeout * 1000) { + vcp_println("ERROR TIMEOUT"); + break; + } + + uint32_t touch_event = touch_get_event(); + if (touch_event != 0) { + uint16_t touch_x = touch_unpack_x(touch_event); + uint16_t touch_y = touch_unpack_y(touch_event); + + if (touch_event & TOUCH_START) { + vcp_println("TOUCH D %d %d %d", touch_x, touch_y, hal_ticks_ms()); + } + if (touch_event & TOUCH_MOVE) { + vcp_println("TOUCH C %d %d %d", touch_x, touch_y, hal_ticks_ms()); + } + if (touch_event & TOUCH_END) { + vcp_println("TOUCH U %d %d %d", touch_x, touch_y, hal_ticks_ms()); + vcp_println("OK"); + break; + } + } + } + + display_clear(); + display_refresh(); + + touch_deinit(); +} + +static void test_touch_idle(const char *args) { + static const int expected_params = 1; + int num_params = 0; + + int params[expected_params]; + + extract_params(args, params, &num_params, expected_params); + + if (num_params != expected_params) { + vcp_println("ERROR PARAM"); + return; + } + + int timeout = params[0]; + + uint32_t ticks_start = hal_ticks_ms(); + + display_clear(); + display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2, "DON'T TOUCH", -1, + FONT_BOLD, COLOR_WHITE, COLOR_BLACK); + display_refresh(); + + touch_init(); + + while (true) { + if (hal_ticks_ms() - ticks_start > timeout * 1000) { + vcp_println("OK"); + break; + } + + if (touch_activity() == sectrue) { + vcp_println("ERROR TOUCH DETECTED"); + break; + } + } + + display_clear(); + display_refresh(); + + touch_deinit(); } static void test_sensitivity(const char *args) { int v = atoi(args); - touch_power_on(); - touch_sensitivity(v & 0xFF); + touch_init(); + touch_set_sensitivity(v & 0xFF); display_clear(); display_refresh(); for (;;) { - uint32_t evt = touch_read(); + uint32_t evt = touch_get_event(); if (evt & TOUCH_START || evt & TOUCH_MOVE) { int x = touch_unpack_x(evt); int y = touch_unpack_y(evt); @@ -386,12 +518,14 @@ static void test_sensitivity(const char *args) { } } - touch_power_off(); + touch_deinit(); } static void touch_version(void) { + touch_init(); uint8_t version = touch_get_version(); vcp_println("OK %d", version); + touch_deinit(); } #endif @@ -458,15 +592,34 @@ static void test_firmware_version(void) { vcp_println("OK %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); } +static uint32_t read_bootloader_version(void) { + const image_header *header = read_image_header( + (const uint8_t *)BOOTLOADER_START, BOOTLOADER_IMAGE_MAGIC, 0xffffffff); + + if (secfalse == header) { + return 0; + } + + return header->version; +} + +static void test_bootloader_version(uint32_t version) { + vcp_println("OK %d.%d.%d", version & 0xFF, (version >> 8) & 0xFF, + (version >> 16) & 0xFF); +} + +static const boardloader_version_t *read_boardloader_version(void) { + parse_boardloader_capabilities(); + return get_boardloader_version(); +} + +static void test_boardloader_version(const boardloader_version_t *version) { + vcp_println("OK %d.%d.%d", version->version_major, version->version_minor, + version->version_patch); +} + static void test_wipe(void) { - // erase start of the firmware (metadata) -> invalidate FW - ensure(flash_unlock_write(), NULL); - for (int i = 0; i < (1024 / FLASH_BLOCK_SIZE); i += FLASH_BLOCK_SIZE) { - flash_block_t data = {0}; - ensure(flash_area_write_block(&FIRMWARE_AREA, i * FLASH_BLOCK_SIZE, data), - NULL); - } - ensure(flash_lock_write(), NULL); + invalidate_firmware(); display_clear(); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); @@ -608,6 +761,8 @@ static void test_otp_write_device_variant(const char *args) { vcp_println("OK"); } +static void test_reboot(void) { svc_reboot(); } + void cpuid_read(void) { uint32_t cpuid[3]; cpuid[0] = LL_GetUID_Word0(); @@ -650,6 +805,9 @@ int main(void) { #endif usb_init_all(); + uint32_t bootloader_version = read_bootloader_version(); + const boardloader_version_t *boardloader_version = read_boardloader_version(); + mpu_config_prodtest_initial(); #ifdef USE_OPTIGA @@ -673,6 +831,7 @@ int main(void) { display_qrcode(DISPLAY_RESX / 2, DISPLAY_RESY / 2, dom, 4); display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY - 30, dom + 8, -1, FONT_BOLD, COLOR_WHITE, COLOR_BLACK); + display_refresh(); } display_fade(0, BACKLIGHT_NORMAL, 1000); @@ -705,6 +864,12 @@ int main(void) { } else if (startswith(line, "TOUCH ")) { test_touch(line + 6); + } else if (startswith(line, "TOUCH_CUSTOM ")) { + test_touch_custom(line + 13); + + } else if (startswith(line, "TOUCH_IDLE ")) { + test_touch_idle(line + 11); + } else if (startswith(line, "SENS ")) { test_sensitivity(line + 5); @@ -763,10 +928,14 @@ int main(void) { } else if (startswith(line, "FIRMWARE VERSION")) { test_firmware_version(); - + } else if (startswith(line, "BOOTLOADER VERSION")) { + test_bootloader_version(bootloader_version); + } else if (startswith(line, "BOARDLOADER VERSION")) { + test_boardloader_version(boardloader_version); } else if (startswith(line, "WIPE")) { test_wipe(); - + } else if (startswith(line, "REBOOT")) { + test_reboot(); } else { vcp_println("UNKNOWN"); } diff --git a/core/embed/prodtest/memory_stm32u5a.ld b/core/embed/prodtest/memory_stm32u5a.ld index 1cdefad795..fa303b5d4f 100644 --- a/core/embed/prodtest/memory_stm32u5a.ld +++ b/core/embed/prodtest/memory_stm32u5a.ld @@ -59,7 +59,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/prodtest/optiga_prodtest.c b/core/embed/prodtest/optiga_prodtest.c index 616a0d4465..bdcdb9f77a 100644 --- a/core/embed/prodtest/optiga_prodtest.c +++ b/core/embed/prodtest/optiga_prodtest.c @@ -143,6 +143,12 @@ void pair_optiga(void) { uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; if (secret_optiga_get(secret) != sectrue) { + if (secret_optiga_writable() != sectrue) { + // optiga pairing secret is unwritable, so fail + optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_FLASH; + return; + } + // Generate the pairing secret. if (OPTIGA_SUCCESS != optiga_get_random(secret, sizeof(secret))) { optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG; diff --git a/core/embed/prodtest/version.h b/core/embed/prodtest/version.h index 15d2074830..de0fc71ec1 100644 --- a/core/embed/prodtest/version.h +++ b/core/embed/prodtest/version.h @@ -1,11 +1,13 @@ +#pragma once + +#include "model_version.h" + #define VERSION_MAJOR 0 #define VERSION_MINOR 2 -#define VERSION_PATCH 6 +#define VERSION_PATCH 9 #define VERSION_BUILD 0 #define FIX_VERSION_MAJOR 0 #define FIX_VERSION_MINOR 2 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 - -#define VERSION_MONOTONIC 1 diff --git a/core/embed/reflash/header.S b/core/embed/reflash/header.S index ce84552baa..2c101aa43c 100644 --- a/core/embed/reflash/header.S +++ b/core/embed/reflash/header.S @@ -26,7 +26,7 @@ g_header: .byte FIX_VERSION_BUILD // fix_vbuild .word HW_MODEL // type of the designated hardware .byte HW_REVISION // revision of the designated hardware - .byte VERSION_MONOTONIC // monotonic version of the binary + .byte FIRMWARE_MONOTONIC_VERSION // monotonic version of the binary . = . + 2 // reserved . = . + 512 // hash1 ... hash16 . = . + 415 // reserved diff --git a/core/embed/reflash/main.c b/core/embed/reflash/main.c index 06b3b2d3a4..b98a3bceb7 100644 --- a/core/embed/reflash/main.c +++ b/core/embed/reflash/main.c @@ -25,6 +25,7 @@ #include "common.h" #include "display.h" +#include "display_draw.h" #include "flash.h" #include "image.h" #include "model.h" diff --git a/core/embed/reflash/memory_stm32u5a.ld b/core/embed/reflash/memory_stm32u5a.ld index be0db29b4b..e03a321847 100644 --- a/core/embed/reflash/memory_stm32u5a.ld +++ b/core/embed/reflash/memory_stm32u5a.ld @@ -60,7 +60,7 @@ SECTIONS { KEEP(*(.header)); } >FLASH AT>FLASH - .flash : ALIGN(512) { + .flash : ALIGN(1024) { KEEP(*(.vector_table)); . = ALIGN(4); *(.text*); diff --git a/core/embed/reflash/version.h b/core/embed/reflash/version.h index 2279c0cc06..07bd5a3a10 100644 --- a/core/embed/reflash/version.h +++ b/core/embed/reflash/version.h @@ -1,3 +1,7 @@ +#pragma once + +#include "model_version.h" + #define VERSION_MAJOR 0 #define VERSION_MINOR 1 #define VERSION_PATCH 0 @@ -7,5 +11,3 @@ #define FIX_VERSION_MINOR 1 #define FIX_VERSION_PATCH 0 #define FIX_VERSION_BUILD 0 - -#define VERSION_MONOTONIC 1 diff --git a/core/embed/rust/Cargo.lock b/core/embed/rust/Cargo.lock index 9cbd4f8285..70ce5e4281 100644 --- a/core/embed/rust/Cargo.lock +++ b/core/embed/rust/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "alloc-traits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483" + [[package]] name = "autocfg" version = "1.1.0" @@ -10,9 +16,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bindgen" -version = "0.60.1" +version = "0.62.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" +checksum = "c6720a8b7b2d39dd533285ed438d458f65b31b5c257e6ac7bb3d7e82844dd722" dependencies = [ "bitflags", "cexpr", @@ -25,6 +31,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", + "syn", ] [[package]] @@ -71,22 +78,21 @@ dependencies = [ "libloading", ] -[[package]] -name = "cstr_core" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd98742e4fdca832d40cab219dc2e3048de17d873248f83f17df47c1bea70956" -dependencies = [ - "cty", - "memchr", -] - [[package]] name = "cty" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "easer" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba524f8b83c9c5bde02c2bb1627de9d1f81980489a6d54168cdfd08c258f917" +dependencies = [ + "num-traits", +] + [[package]] name = "glob" version = "0.3.0" @@ -147,6 +153,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "memchr" version = "2.4.1" @@ -182,11 +194,20 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", +] + +[[package]] +name = "pareen" +version = "0.3.3" +dependencies = [ + "easer", + "num-traits", ] [[package]] @@ -197,11 +218,11 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "proc-macro2" -version = "1.0.29" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f5105d4fdaab20335ca9565e106a5d9b82b6219b5ba735731124ac6711d23d" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -279,15 +300,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static-alloc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "570b7e840addf99f80c5b26abba410e21537002316fc82f2747fd87c171e9d7e" +dependencies = [ + "alloc-traits", +] + [[package]] name = "syn" -version = "1.0.80" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -300,17 +330,21 @@ version = "0.1.0" dependencies = [ "bindgen", "cc", - "cstr_core", "cty", + "easer", "glob", "heapless", "num-derive", "num-traits", + "pareen", "qrcodegen", "serde_json", "spin", + "static-alloc", "trezor-tjpgdec", "ufmt", + "unsize", + "without-alloc", "zeroize", ] @@ -342,10 +376,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unsize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa7a7a734c1a5664a662ddcea0b6c9472a21da8888c957c7f1eaa09dba7a939" +dependencies = [ + "autocfg", +] [[package]] name = "winapi" @@ -369,6 +412,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "without-alloc" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "375db0478b203b950ef10d1cce23cdbe5f30c2454fd9e7673ff56656df23adbb" +dependencies = [ + "alloc-traits", + "unsize", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/core/embed/rust/Cargo.toml b/core/embed/rust/Cargo.toml index 2faab74a7e..77091f4326 100644 --- a/core/embed/rust/Cargo.toml +++ b/core/embed/rust/Cargo.toml @@ -15,10 +15,21 @@ micropython = [] protobuf = ["micropython"] ui = [] dma2d = [] +xframebuffer = [] +display_mono = [] +display_rgb565 = ["ui_antialiasing"] +display_rgba8888 = ["ui_antialiasing"] framebuffer = [] framebuffer32bit = [] ui_debug = [] -ui_bounds = [] +ui_antialiasing = [] +ui_blurring = [] +ui_jpeg_decoder = ["jpeg"] +ui_image_buffer = [] +ui_color_32bit = [] +ui_overlay = [] +ui_empty_lock = [] +new_rendering = [] bootloader = [] button = [] touch = [] @@ -36,19 +47,25 @@ usb = [] optiga = [] translations = ["crypto"] test = [ + "backlight", "button", "cc", "crypto", + "dma2d", "debug", "glob", "micropython", + "new_rendering", + "optiga", "protobuf", - "ui", - "dma2d", "touch", - "backlight", - "optiga", "translations", + "ui", + "ui_jpeg_decoder", + "ui_blurring", + "ui_image_buffer", + "ui_overlay", + "ui_empty_lock", "universal_fw", ] universal_fw = [] @@ -94,21 +111,38 @@ features = ["ufmt"] default_features = false [dependencies.num-traits] -version = "0.2.15" +version = "0.2.18" default_features = false +features = ["libm"] [dependencies.num-derive] version = "0.3.3" -[dependencies.cstr_core] -version = "0.2.6" +[dependencies.static-alloc] +version = "0.2.4" + +[dependencies.without-alloc] +version = "0.2.2" + +[dependencies.unsize] +version = "1.1.0" + +[dependencies.pareen] +version = "0.3.3" +path = "../../../rust/pareen" default-features = false -features = ["nightly"] +features = ["libm", "easer"] + +[dependencies.easer] +version = "0.3.0" +default-features = false +features = ["libm"] + # Build dependencies [build-dependencies.bindgen] -version = "0.60.1" +version = "0.62.0" default_features = false features = ["runtime"] diff --git a/core/embed/rust/build.rs b/core/embed/rust/build.rs index fffd32346c..6f2706e555 100644 --- a/core/embed/rust/build.rs +++ b/core/embed/rust/build.rs @@ -14,12 +14,67 @@ fn main() { link_core_objects(); } -// fn block_words() -> String { -// match env::var("FLASH_BLOCK_WORDS") { -// Ok(model) => model, -// Err(_) => panic!("FLASH_BLOCK_WORDS not set") -// } -// } +const DEFAULT_BINDGEN_MACROS_COMMON: &[&str] = &[ + "-I../unix", + "-I../trezorhal/unix", + "-I../../build/unix", + "-I../../vendor/micropython/ports/unix", + "-I../../../crypto", + "-I../../../storage", + "-I../../vendor/micropython", + "-I../../vendor/micropython/lib/uzlib", + "-I../lib", + "-I../trezorhal", + "-I../trezorhal/unix", + "-I../models", + "-DTREZOR_EMULATOR", +]; + +#[cfg(feature = "model_tt")] +const DEFAULT_BINDGEN_MACROS_T2T1: &[&str] = &[ + "-DSTM32F427", + "-DTREZOR_MODEL_T", + "-DFLASH_BIT_ACCESS=1", + "-DFLASH_BLOCK_WORDS=1", + "-DTREZOR_BOARD=\"T2T1/boards/t2t1-unix.h\"", +]; +#[cfg(not(feature = "model_tt"))] +const DEFAULT_BINDGEN_MACROS_T2T1: &[&str] = &[]; + +#[cfg(feature = "model_tr")] +const DEFAULT_BINDGEN_MACROS_T2B1: &[&str] = &[ + "-DSTM32F427", + "-DTREZOR_MODEL_R", + "-DFLASH_BIT_ACCESS=1", + "-DFLASH_BLOCK_WORDS=1", + "-DTREZOR_BOARD=\"T2B1/boards/t2b1-unix.h\"", +]; +#[cfg(not(feature = "model_tr"))] +const DEFAULT_BINDGEN_MACROS_T2B1: &[&str] = &[]; + +#[cfg(feature = "model_mercury")] +const DEFAULT_BINDGEN_MACROS_T3T1: &[&str] = &[ + "-DSTM32U5", + "-DTREZOR_MODEL_T3T1", + "-DFLASH_BIT_ACCESS=0", + "-DFLASH_BLOCK_WORDS=4", + "-DTREZOR_BOARD=\"T3T1/boards/t3t1-unix.h\"", +]; +#[cfg(not(feature = "model_mercury"))] +const DEFAULT_BINDGEN_MACROS_T3T1: &[&str] = &[]; + +fn add_bindgen_macros<'a>(clang_args: &mut Vec<&'a str>, envvar: Option<&'a str>) { + let default_macros = DEFAULT_BINDGEN_MACROS_COMMON + .iter() + .chain(DEFAULT_BINDGEN_MACROS_T2T1) + .chain(DEFAULT_BINDGEN_MACROS_T2B1) + .chain(DEFAULT_BINDGEN_MACROS_T3T1); + + match envvar { + Some(envvar) => clang_args.extend(envvar.split(',')), + None => clang_args.extend(default_macros), + } +} /// Generates Rust module that exports QSTR constants used in firmware. #[cfg(feature = "micropython")] @@ -34,7 +89,10 @@ fn generate_qstr_bindings() { bindgen::Builder::default() .header("qstr.h") // Build the Qstr enum as a newtype so we can define method on it. - .default_enum_style(bindgen::EnumVariation::NewType { is_bitfield: false }) + .default_enum_style(bindgen::EnumVariation::NewType { + is_bitfield: false, + is_global: false, + }) // Pass in correct include paths. .clang_args(&[ "-I", @@ -70,11 +128,18 @@ fn prepare_bindings() -> bindgen::Builder { let mut bindings = bindgen::Builder::default(); let mut clang_args: Vec<&str> = Vec::new(); - let includes = env::var("BINDGEN_MACROS").unwrap(); - let args = includes.split(','); - for arg in args { - clang_args.push(arg); + let bindgen_macros_env = env::var("BINDGEN_MACROS").ok(); + add_bindgen_macros(&mut clang_args, bindgen_macros_env.as_deref()); + + #[cfg(feature = "xframebuffer")] + { + bindings = bindings.clang_args(&["-DXFRAMEBUFFER"]); + } + + #[cfg(feature = "new_rendering")] + { + bindings = bindings.clang_args(["-DNEW_RENDERING"]); } // Pass in correct include paths and defines. @@ -170,6 +235,8 @@ fn generate_micropython_bindings() { .allowlist_var("mp_type_fun_builtin_var") // gc .allowlist_function("gc_alloc") + .allowlist_function("gc_free") + .allowlist_var("GC_ALLOC_FLAG_HAS_FINALISER") // iter .allowlist_type("mp_obj_iter_buf_t") .allowlist_function("mp_getiter") @@ -289,6 +356,29 @@ fn generate_trezorhal_bindings() { .allowlist_var("DISPLAY_FRAMEBUFFER_OFFSET_Y") .allowlist_var("DISPLAY_RESX") .allowlist_var("DISPLAY_RESY") + .allowlist_type("display_fb_info_t") + .allowlist_function("display_get_frame_buffer") + .allowlist_function("display_fill") + .allowlist_function("display_copy_rgb565") + // gfx_bitblt + .allowlist_type("gfx_bitblt_t") + .allowlist_function("gfx_rgb565_fill") + .allowlist_function("gfx_rgb565_copy_mono4") + .allowlist_function("gfx_rgb565_copy_rgb565") + .allowlist_function("gfx_rgb565_blend_mono4") + .allowlist_function("gfx_rgb565_blend_mono8") + .allowlist_function("gfx_rgba8888_fill") + .allowlist_function("gfx_rgba8888_copy_mono4") + .allowlist_function("gfx_rgba8888_copy_rgb565") + .allowlist_function("gfx_rgba8888_copy_rgba8888") + .allowlist_function("gfx_rgba8888_blend_mono4") + .allowlist_function("gfx_rgba8888_blend_mono8") + .allowlist_function("gfx_mono8_fill") + .allowlist_function("gfx_mono8_copy_mono1p") + .allowlist_function("gfx_mono8_copy_mono4") + .allowlist_function("gfx_mono8_blend_mono1p") + .allowlist_function("gfx_mono8_blend_mono4") + .allowlist_function("dma2d_wait") // fonts .allowlist_function("font_height") .allowlist_function("font_max_height") @@ -353,12 +443,13 @@ fn generate_trezorhal_bindings() { //usb .allowlist_function("usb_configured") // touch - .allowlist_function("touch_read") + .allowlist_function("touch_get_event") // button .allowlist_function("button_read") // haptic .allowlist_type("haptic_effect_t") - .allowlist_function("haptic_play"); + .allowlist_function("haptic_play") + .allowlist_function("haptic_play_custom"); // Write the bindings to a file in the OUR_DIR. bindings diff --git a/core/embed/rust/librust_qstr.h b/core/embed/rust/librust_qstr.h index 0512b15891..6daa251c29 100644 --- a/core/embed/rust/librust_qstr.h +++ b/core/embed/rust/librust_qstr.h @@ -6,20 +6,36 @@ static void _librust_qstrs(void) { MP_QSTR_; + MP_QSTR_AttachType; + MP_QSTR_BacklightLevels; MP_QSTR_CANCELLED; MP_QSTR_CONFIRMED; + MP_QSTR_DIM; MP_QSTR_INFO; + MP_QSTR_INITIAL; + MP_QSTR_LOW; MP_QSTR_LayoutObj; + MP_QSTR_MAX; MP_QSTR_MESSAGE_NAME; MP_QSTR_MESSAGE_WIRE_TYPE; MP_QSTR_Msg; MP_QSTR_MsgDef; + MP_QSTR_NONE; + MP_QSTR_NORMAL; + MP_QSTR_RESUME; + MP_QSTR_SWIPE_DOWN; + MP_QSTR_SWIPE_LEFT; + MP_QSTR_SWIPE_RIGHT; + MP_QSTR_SWIPE_UP; MP_QSTR_TR; MP_QSTR_TranslationsHeader; + MP_QSTR___del__; MP_QSTR___dict__; MP_QSTR___name__; MP_QSTR_account; + MP_QSTR_account_items; MP_QSTR_account_label; + MP_QSTR_account_path; MP_QSTR_accounts; MP_QSTR_action; MP_QSTR_active; @@ -30,14 +46,21 @@ static void _librust_qstrs(void) { MP_QSTR_addr_mismatch__wrong_derivation_path; MP_QSTR_addr_mismatch__xpub_mismatch; MP_QSTR_address; + MP_QSTR_address__cancel_contact_support; + MP_QSTR_address__cancel_receive; + MP_QSTR_address__confirmed; MP_QSTR_address__public_key; + MP_QSTR_address__qr_code; MP_QSTR_address__title_cosigner; MP_QSTR_address__title_receive_address; MP_QSTR_address__title_yours; + MP_QSTR_address_details__account_info; MP_QSTR_address_details__derivation_path; + MP_QSTR_address_details__derivation_path_colon; MP_QSTR_address_details__title_receive_address; MP_QSTR_address_details__title_receiving_to; MP_QSTR_address_label; + MP_QSTR_address_qr; MP_QSTR_address_title; MP_QSTR_allow_cancel; MP_QSTR_altcoin_tx_summary; @@ -53,13 +76,19 @@ static void _librust_qstrs(void) { MP_QSTR_authenticate__header; MP_QSTR_auto_lock__change_template; MP_QSTR_auto_lock__title; + MP_QSTR_auto_lock__turned_on; MP_QSTR_backup__can_back_up_anytime; + MP_QSTR_backup__create_backup_to_prevent_loss; + MP_QSTR_backup__info_multi_share_backup; + MP_QSTR_backup__info_single_share_backup; MP_QSTR_backup__it_should_be_backed_up; MP_QSTR_backup__it_should_be_backed_up_now; MP_QSTR_backup__new_wallet_created; MP_QSTR_backup__new_wallet_successfully_created; MP_QSTR_backup__recover_anytime; + MP_QSTR_backup__title_backup_completed; MP_QSTR_backup__title_backup_wallet; + MP_QSTR_backup__title_create_wallet_backup; MP_QSTR_backup__title_skip; MP_QSTR_backup__want_to_skip; MP_QSTR_bitcoin__commitment_data; @@ -90,9 +119,14 @@ static void _librust_qstrs(void) { MP_QSTR_bitcoin__valid_signature; MP_QSTR_bitcoin__voting_rights; MP_QSTR_bootscreen; - MP_QSTR_bounds; + MP_QSTR_br_code; + MP_QSTR_br_name; + MP_QSTR_brightness__change_title; + MP_QSTR_brightness__changed_title; + MP_QSTR_brightness__title; MP_QSTR_button; MP_QSTR_button_event; + MP_QSTR_button_request; MP_QSTR_buttons__abort; MP_QSTR_buttons__access; MP_QSTR_buttons__again; @@ -134,6 +168,7 @@ static void _librust_qstrs(void) { MP_QSTR_can_go_back; MP_QSTR_cancel_arrow; MP_QSTR_cancel_cross; + MP_QSTR_cancel_text; MP_QSTR_case_sensitive; MP_QSTR_check_homescreen_format; MP_QSTR_chunkify; @@ -166,12 +201,15 @@ static void _librust_qstrs(void) { MP_QSTR_confirm_reset_device; MP_QSTR_confirm_total; MP_QSTR_confirm_total__fee_rate; + MP_QSTR_confirm_total__fee_rate_colon; MP_QSTR_confirm_total__sending_from_account; MP_QSTR_confirm_total__title_fee; MP_QSTR_confirm_total__title_sending_from; MP_QSTR_confirm_value; MP_QSTR_confirm_with_info; MP_QSTR_count; + MP_QSTR_current; + MP_QSTR_danger; MP_QSTR_data; MP_QSTR_data_hash; MP_QSTR_data_len; @@ -184,7 +222,6 @@ static void _librust_qstrs(void) { MP_QSTR_device_name__change_template; MP_QSTR_device_name__title; MP_QSTR_disable_animation; - MP_QSTR_dry_run; MP_QSTR_encode; MP_QSTR_encoded_length; MP_QSTR_entropy__send; @@ -196,6 +233,7 @@ static void _librust_qstrs(void) { MP_QSTR_experimental_mode__title; MP_QSTR_extra; MP_QSTR_fee_amount; + MP_QSTR_fee_items; MP_QSTR_fee_label; MP_QSTR_fee_rate_amount; MP_QSTR_fee_title; @@ -203,11 +241,32 @@ static void _librust_qstrs(void) { MP_QSTR_fingerprint; MP_QSTR_firmware_update__title; MP_QSTR_firmware_update__title_fingerprint; + MP_QSTR_first_screen; + MP_QSTR_flow_confirm_output; + MP_QSTR_flow_confirm_reset; + MP_QSTR_flow_confirm_set_new_pin; + MP_QSTR_flow_confirm_summary; + MP_QSTR_flow_continue_recovery; + MP_QSTR_flow_get_address; + MP_QSTR_flow_prompt_backup; + MP_QSTR_flow_request_number; + MP_QSTR_flow_request_passphrase; + MP_QSTR_flow_show_share_words; + MP_QSTR_flow_warning_hi_prio; MP_QSTR_get_language; + MP_QSTR_get_transition_out; + MP_QSTR_haptic_feedback__disable; + MP_QSTR_haptic_feedback__enable; + MP_QSTR_haptic_feedback__subtitle; + MP_QSTR_haptic_feedback__title; + MP_QSTR_highlight_repeated; MP_QSTR_hold; MP_QSTR_hold_danger; MP_QSTR_homescreen__click_to_connect; MP_QSTR_homescreen__click_to_unlock; + MP_QSTR_homescreen__set_default; + MP_QSTR_homescreen__settings_subtitle; + MP_QSTR_homescreen__settings_title; MP_QSTR_homescreen__title_backup_failed; MP_QSTR_homescreen__title_backup_needed; MP_QSTR_homescreen__title_coinjoin_authorized; @@ -220,6 +279,7 @@ static void _librust_qstrs(void) { MP_QSTR_icon_name; MP_QSTR_image; MP_QSTR_indeterminate; + MP_QSTR_info; MP_QSTR_info_button; MP_QSTR_init; MP_QSTR_inputs__back; @@ -230,6 +290,22 @@ static void _librust_qstrs(void) { MP_QSTR_inputs__return; MP_QSTR_inputs__show; MP_QSTR_inputs__space; + MP_QSTR_instructions__continue_holding; + MP_QSTR_instructions__continue_in_app; + MP_QSTR_instructions__enter_next_share; + MP_QSTR_instructions__hold_to_confirm; + MP_QSTR_instructions__hold_to_continue; + MP_QSTR_instructions__hold_to_exit_tutorial; + MP_QSTR_instructions__hold_to_finish_tutorial; + MP_QSTR_instructions__hold_to_sign; + MP_QSTR_instructions__learn_more; + MP_QSTR_instructions__shares_continue_with_x_template; + MP_QSTR_instructions__shares_start_with_1; + MP_QSTR_instructions__swipe_down; + MP_QSTR_instructions__swipe_horizontally; + MP_QSTR_instructions__swipe_up; + MP_QSTR_instructions__tap_to_confirm; + MP_QSTR_instructions__tap_to_start; MP_QSTR_is_type_of; MP_QSTR_items; MP_QSTR_joint__title; @@ -251,6 +327,7 @@ static void _librust_qstrs(void) { MP_QSTR_max_feerate; MP_QSTR_max_len; MP_QSTR_max_rounds; + MP_QSTR_message; MP_QSTR_min_count; MP_QSTR_misc__decrypt_value; MP_QSTR_misc__encrypt_value; @@ -272,10 +349,10 @@ static void _librust_qstrs(void) { MP_QSTR_page_count; MP_QSTR_pages; MP_QSTR_paint; - MP_QSTR_passphrase__access_hidden_wallet; + MP_QSTR_passphrase__access_wallet; MP_QSTR_passphrase__always_on_device; + MP_QSTR_passphrase__continue_with_empty_passphrase; MP_QSTR_passphrase__from_host_not_shown; - MP_QSTR_passphrase__hidden_wallet; MP_QSTR_passphrase__hide; MP_QSTR_passphrase__next_screen_will_show_passphrase; MP_QSTR_passphrase__please_enter; @@ -283,11 +360,16 @@ static void _librust_qstrs(void) { MP_QSTR_passphrase__title_confirm; MP_QSTR_passphrase__title_enter; MP_QSTR_passphrase__title_hide; + MP_QSTR_passphrase__title_passphrase; MP_QSTR_passphrase__title_settings; MP_QSTR_passphrase__title_source; MP_QSTR_passphrase__turn_off; MP_QSTR_passphrase__turn_on; + MP_QSTR_passphrase__wallet; MP_QSTR_path; + MP_QSTR_pin__cancel_description; + MP_QSTR_pin__cancel_info; + MP_QSTR_pin__cancel_setup; MP_QSTR_pin__change; MP_QSTR_pin__changed; MP_QSTR_pin__cursor_will_change; @@ -335,24 +417,34 @@ static void _librust_qstrs(void) { MP_QSTR_progress__x_seconds_left_template; MP_QSTR_progress_event; MP_QSTR_prompt; + MP_QSTR_prompt_screen; + MP_QSTR_prompt_title; MP_QSTR_qr_title; MP_QSTR_reboot_to_bootloader__just_a_moment; MP_QSTR_reboot_to_bootloader__restart; MP_QSTR_reboot_to_bootloader__title; MP_QSTR_reboot_to_bootloader__version_by_template; + MP_QSTR_recovery; MP_QSTR_recovery__cancel_dry_run; MP_QSTR_recovery__check_dry_run; MP_QSTR_recovery__cursor_will_change; + MP_QSTR_recovery__dry_run_backup_not_on_this_device; MP_QSTR_recovery__dry_run_bip39_valid_match; MP_QSTR_recovery__dry_run_bip39_valid_mismatch; + MP_QSTR_recovery__dry_run_invalid_backup_entered; + MP_QSTR_recovery__dry_run_slip39_valid_all_shares; MP_QSTR_recovery__dry_run_slip39_valid_match; MP_QSTR_recovery__dry_run_slip39_valid_mismatch; + MP_QSTR_recovery__dry_run_slip39_valid_share; + MP_QSTR_recovery__dry_run_verify_remaining_shares; MP_QSTR_recovery__enter_any_share; MP_QSTR_recovery__enter_backup; MP_QSTR_recovery__enter_different_share; + MP_QSTR_recovery__enter_each_word; MP_QSTR_recovery__enter_share_from_diff_group; MP_QSTR_recovery__group_num_template; MP_QSTR_recovery__group_threshold_reached; + MP_QSTR_recovery__info_about_disconnect; MP_QSTR_recovery__invalid_share_entered; MP_QSTR_recovery__invalid_wallet_backup_entered; MP_QSTR_recovery__more_shares_needed; @@ -361,7 +453,8 @@ static void _librust_qstrs(void) { MP_QSTR_recovery__progress_will_be_lost; MP_QSTR_recovery__select_num_of_words; MP_QSTR_recovery__share_already_entered; - MP_QSTR_recovery__share_from_another_shamir; + MP_QSTR_recovery__share_does_not_match; + MP_QSTR_recovery__share_from_another_multi_share_backup; MP_QSTR_recovery__share_num_template; MP_QSTR_recovery__title; MP_QSTR_recovery__title_cancel_dry_run; @@ -369,7 +462,10 @@ static void _librust_qstrs(void) { MP_QSTR_recovery__title_dry_run; MP_QSTR_recovery__title_recover; MP_QSTR_recovery__title_remaining_shares; + MP_QSTR_recovery__title_unlock_repeated_backup; MP_QSTR_recovery__type_word_x_of_y_template; + MP_QSTR_recovery__unlock_repeated_backup; + MP_QSTR_recovery__unlock_repeated_backup_verb; MP_QSTR_recovery__wallet_recovered; MP_QSTR_recovery__wanna_cancel_dry_run; MP_QSTR_recovery__wanna_cancel_recovery; @@ -379,6 +475,7 @@ static void _librust_qstrs(void) { MP_QSTR_recovery__x_more_shares_needed_template_plural; MP_QSTR_recovery__x_of_y_entered_template; MP_QSTR_recovery__you_have_entered; + MP_QSTR_recovery_type; MP_QSTR_request_bip39; MP_QSTR_request_complete_repaint; MP_QSTR_request_number; @@ -391,13 +488,15 @@ static void _librust_qstrs(void) { MP_QSTR_reset__button_create; MP_QSTR_reset__button_recover; MP_QSTR_reset__by_continuing; + MP_QSTR_reset__cancel_create_wallet; + MP_QSTR_reset__check_backup_instructions; MP_QSTR_reset__check_backup_title; MP_QSTR_reset__check_group_share_title_template; MP_QSTR_reset__check_share_title_template; MP_QSTR_reset__check_wallet_backup_title; MP_QSTR_reset__continue_with_next_share; MP_QSTR_reset__continue_with_share_template; - MP_QSTR_reset__create_x_of_y_shamir_backup_template; + MP_QSTR_reset__create_x_of_y_multi_share_backup_template; MP_QSTR_reset__finished_verifying_group_template; MP_QSTR_reset__finished_verifying_shares; MP_QSTR_reset__finished_verifying_wallet_backup; @@ -405,6 +504,8 @@ static void _librust_qstrs(void) { MP_QSTR_reset__group_info; MP_QSTR_reset__group_share_checked_successfully_template; MP_QSTR_reset__group_share_title_template; + MP_QSTR_reset__incorrect_word_selected; + MP_QSTR_reset__more_at; MP_QSTR_reset__more_info_at; MP_QSTR_reset__need_all_share_template; MP_QSTR_reset__need_any_share_template; @@ -413,31 +514,42 @@ static void _librust_qstrs(void) { MP_QSTR_reset__never_make_digital_copy; MP_QSTR_reset__num_of_share_holders_template; MP_QSTR_reset__num_of_shares_advanced_info_template; - MP_QSTR_reset__num_of_shares_basic_info; + MP_QSTR_reset__num_of_shares_basic_info_template; + MP_QSTR_reset__num_of_shares_how_many; + MP_QSTR_reset__num_of_shares_long_info_template; MP_QSTR_reset__num_shares_for_group_template; MP_QSTR_reset__number_of_shares_info; MP_QSTR_reset__one_share; MP_QSTR_reset__only_one_share_will_be_created; MP_QSTR_reset__recovery_share_title_template; MP_QSTR_reset__recovery_wallet_backup_title; + MP_QSTR_reset__repeat_for_all_shares; MP_QSTR_reset__required_number_of_groups; MP_QSTR_reset__select_correct_word; + MP_QSTR_reset__select_threshold; MP_QSTR_reset__select_word_template; MP_QSTR_reset__select_word_x_of_y_template; MP_QSTR_reset__set_it_to_count_template; MP_QSTR_reset__share_checked_successfully_template; + MP_QSTR_reset__share_completed_template; MP_QSTR_reset__share_words_title; + MP_QSTR_reset__slip39_checklist_more_info_threshold; + MP_QSTR_reset__slip39_checklist_more_info_threshold_example_template; MP_QSTR_reset__slip39_checklist_num_groups; + MP_QSTR_reset__slip39_checklist_num_groups_x_template; MP_QSTR_reset__slip39_checklist_num_shares; + MP_QSTR_reset__slip39_checklist_num_shares_x_template; MP_QSTR_reset__slip39_checklist_set_num_groups; MP_QSTR_reset__slip39_checklist_set_num_shares; MP_QSTR_reset__slip39_checklist_set_sizes; MP_QSTR_reset__slip39_checklist_set_sizes_longer; MP_QSTR_reset__slip39_checklist_set_threshold; + MP_QSTR_reset__slip39_checklist_threshold_x_template; MP_QSTR_reset__slip39_checklist_title; MP_QSTR_reset__slip39_checklist_write_down; MP_QSTR_reset__slip39_checklist_write_down_recovery; MP_QSTR_reset__the_threshold_sets_the_number_of_shares; + MP_QSTR_reset__the_word_is_repeated; MP_QSTR_reset__threshold_info; MP_QSTR_reset__title_backup_is_done; MP_QSTR_reset__title_create_wallet; @@ -454,6 +566,8 @@ static void _librust_qstrs(void) { MP_QSTR_reset__tos_link; MP_QSTR_reset__total_number_of_shares_in_group_template; MP_QSTR_reset__use_your_backup; + MP_QSTR_reset__words_may_repeat; + MP_QSTR_reset__words_written_down_template; MP_QSTR_reset__write_down_words_template; MP_QSTR_reset__wrong_word_selected; MP_QSTR_reset__you_need_one_share; @@ -495,11 +609,15 @@ static void _librust_qstrs(void) { MP_QSTR_select_word; MP_QSTR_select_word_count; MP_QSTR_send__address_path; + MP_QSTR_send__cancel_sign; MP_QSTR_send__confirm_sending; MP_QSTR_send__from_multiple_accounts; + MP_QSTR_send__incl_transaction_fee; MP_QSTR_send__including_fee; MP_QSTR_send__maximum_fee; MP_QSTR_send__receiving_to_multisig; + MP_QSTR_send__send_from; + MP_QSTR_send__sign_transaction; MP_QSTR_send__title_confirm_sending; MP_QSTR_send__title_joint_transaction; MP_QSTR_send__title_receiving_to; @@ -508,8 +626,13 @@ static void _librust_qstrs(void) { MP_QSTR_send__title_sending_to; MP_QSTR_send__to_the_total_amount; MP_QSTR_send__total_amount; + MP_QSTR_send__total_amount_colon; MP_QSTR_send__transaction_id; + MP_QSTR_send__transaction_signed; MP_QSTR_send__you_are_contributing; + MP_QSTR_set_brightness; + MP_QSTR_setting__adjust; + MP_QSTR_setting__apply; MP_QSTR_share_words; MP_QSTR_share_words__words_in_order; MP_QSTR_share_words__wrote_down_all; @@ -544,7 +667,15 @@ static void _librust_qstrs(void) { MP_QSTR_storage_msg__verifying_pin; MP_QSTR_storage_msg__wrong_pin; MP_QSTR_subprompt; + MP_QSTR_subtext; MP_QSTR_subtitle; + MP_QSTR_summary_br_code; + MP_QSTR_summary_br_name; + MP_QSTR_summary_items; + MP_QSTR_summary_title; + MP_QSTR_text; + MP_QSTR_text_confirm; + MP_QSTR_text_info; MP_QSTR_text_mono; MP_QSTR_time_ms; MP_QSTR_timer; @@ -558,17 +689,37 @@ static void _librust_qstrs(void) { MP_QSTR_trezorproto; MP_QSTR_trezorui2; MP_QSTR_tutorial; + MP_QSTR_tutorial__continue; + MP_QSTR_tutorial__did_you_know; + MP_QSTR_tutorial__exit; + MP_QSTR_tutorial__first_transaction_finish; + MP_QSTR_tutorial__first_transaction_intro; + MP_QSTR_tutorial__first_wallet; + MP_QSTR_tutorial__get_started; + MP_QSTR_tutorial__lets_begin; + MP_QSTR_tutorial__menu; MP_QSTR_tutorial__middle_click; + MP_QSTR_tutorial__one_more_step; MP_QSTR_tutorial__press_and_hold; MP_QSTR_tutorial__ready_to_use; + MP_QSTR_tutorial__ready_to_use_safe5; + MP_QSTR_tutorial__restart_tutorial; MP_QSTR_tutorial__scroll_down; + MP_QSTR_tutorial__subtitle_safe5; MP_QSTR_tutorial__sure_you_want_skip; + MP_QSTR_tutorial__swipe_up_and_down; + MP_QSTR_tutorial__title_easy_navigation; + MP_QSTR_tutorial__title_handy_menu; MP_QSTR_tutorial__title_hello; + MP_QSTR_tutorial__title_hold; + MP_QSTR_tutorial__title_lets_begin; MP_QSTR_tutorial__title_screen_scroll; MP_QSTR_tutorial__title_skip; MP_QSTR_tutorial__title_tutorial_complete; + MP_QSTR_tutorial__title_well_done; MP_QSTR_tutorial__use_trezor; MP_QSTR_tutorial__welcome_press_right; + MP_QSTR_tutorial__welcome_safe5; MP_QSTR_type_for_name; MP_QSTR_type_for_wire; MP_QSTR_usb_event; @@ -609,6 +760,7 @@ static void _librust_qstrs(void) { MP_QSTR_words__array_of; MP_QSTR_words__blockhash; MP_QSTR_words__buying; + MP_QSTR_words__cancel_and_exit; MP_QSTR_words__confirm; MP_QSTR_words__confirm_fee; MP_QSTR_words__contains; @@ -617,18 +769,25 @@ static void _librust_qstrs(void) { MP_QSTR_words__error; MP_QSTR_words__fee; MP_QSTR_words__from; + MP_QSTR_words__good_to_know; + MP_QSTR_words__important; + MP_QSTR_words__instructions; MP_QSTR_words__keep_it_safe; MP_QSTR_words__know_what_your_doing; MP_QSTR_words__my_trezor; MP_QSTR_words__no; + MP_QSTR_words__not_recommended; + MP_QSTR_words__operation_cancelled; MP_QSTR_words__outputs; MP_QSTR_words__please_check_again; MP_QSTR_words__please_try_again; MP_QSTR_words__really_wanna; MP_QSTR_words__recipient; + MP_QSTR_words__settings; MP_QSTR_words__sign; MP_QSTR_words__signer; MP_QSTR_words__title_check; + MP_QSTR_words__title_done; MP_QSTR_words__title_group; MP_QSTR_words__title_information; MP_QSTR_words__title_remember; @@ -637,6 +796,7 @@ static void _librust_qstrs(void) { MP_QSTR_words__title_success; MP_QSTR_words__title_summary; MP_QSTR_words__title_threshold; + MP_QSTR_words__try_again; MP_QSTR_words__unknown; MP_QSTR_words__warning; MP_QSTR_words__writable; @@ -663,6 +823,8 @@ static void _librust_qstrs(void) { MP_QSTR_cardano__addr_pointer; MP_QSTR_cardano__addr_reward; MP_QSTR_cardano__address_no_staking; + MP_QSTR_cardano__always_abstain; + MP_QSTR_cardano__always_no_confidence; MP_QSTR_cardano__amount_burned_decimals_unknown; MP_QSTR_cardano__amount_minted_decimals_unknown; MP_QSTR_cardano__amount_sent_decimals_unknown; @@ -690,6 +852,9 @@ static void _librust_qstrs(void) { MP_QSTR_cardano__credential_mismatch; MP_QSTR_cardano__datum_hash; MP_QSTR_cardano__delegating_to; + MP_QSTR_cardano__delegating_to_key_hash; + MP_QSTR_cardano__delegating_to_script; + MP_QSTR_cardano__deposit; MP_QSTR_cardano__for_account_and_index_template; MP_QSTR_cardano__for_account_template; MP_QSTR_cardano__for_key_hash; @@ -759,6 +924,7 @@ static void _librust_qstrs(void) { MP_QSTR_cardano__unusual_path; MP_QSTR_cardano__valid_since; MP_QSTR_cardano__verify_script; + MP_QSTR_cardano__vote_delegation; MP_QSTR_cardano__vote_key_registration; MP_QSTR_cardano__vote_public_key; MP_QSTR_cardano__voting_purpose; @@ -795,7 +961,6 @@ static void _librust_qstrs(void) { MP_QSTR_eos__requirement; MP_QSTR_eos__sell_ram; MP_QSTR_eos__sender; - MP_QSTR_eos__sign_transaction; MP_QSTR_eos__threshold; MP_QSTR_eos__to; MP_QSTR_eos__transfer; @@ -845,15 +1010,20 @@ static void _librust_qstrs(void) { MP_QSTR_fido__does_not_belong; MP_QSTR_fido__erase_credentials; MP_QSTR_fido__export_credentials; + MP_QSTR_fido__more_credentials; MP_QSTR_fido__not_registered; MP_QSTR_fido__not_registered_with_template; MP_QSTR_fido__please_enable_pin_protection; + MP_QSTR_fido__select_intro; MP_QSTR_fido__title_authenticate; + MP_QSTR_fido__title_credential_details; + MP_QSTR_fido__title_for_authentication; MP_QSTR_fido__title_import_credential; MP_QSTR_fido__title_list_credentials; MP_QSTR_fido__title_register; MP_QSTR_fido__title_remove_credential; MP_QSTR_fido__title_reset; + MP_QSTR_fido__title_select_credential; MP_QSTR_fido__title_u2f_auth; MP_QSTR_fido__title_u2f_register; MP_QSTR_fido__title_verify_user; diff --git a/core/embed/rust/rust_ui.h b/core/embed/rust/rust_ui.h index d2cc626f99..897c6a3311 100644 --- a/core/embed/rust/rust_ui.h +++ b/core/embed/rust/rust_ui.h @@ -1,5 +1,6 @@ #include #include "common.h" + #include "rust_ui_bootloader.h" #include "rust_ui_common.h" diff --git a/core/embed/rust/rust_ui_bootloader.h b/core/embed/rust/rust_ui_bootloader.h index 09613cf035..cdddb96a51 100644 --- a/core/embed/rust/rust_ui_bootloader.h +++ b/core/embed/rust/rust_ui_bootloader.h @@ -4,7 +4,7 @@ uint32_t screen_install_confirm(const char* vendor_str, uint8_t vendor_str_len, const char* version_str, const uint8_t* fingerprint, bool should_keep_seed, bool is_newvendor, - int version_cmp); + bool is_newinstall, int version_cmp); uint32_t screen_wipe_confirm(void); void screen_install_progress(int16_t progress, bool initialize, bool initial_setup); @@ -24,3 +24,6 @@ void screen_boot_stage_1(bool fading); uint32_t screen_unlock_bootloader_confirm(void); void screen_unlock_bootloader_success(void); void bld_continue_label(uint16_t bg_color); +void screen_boot(bool warning, const char* vendor_str, size_t vendor_str_len, + uint32_t version, const void* vendor_img, + size_t vendor_img_len, int wait); diff --git a/core/embed/rust/rust_ui_common.h b/core/embed/rust/rust_ui_common.h index 4297bd39a5..11f03965a8 100644 --- a/core/embed/rust/rust_ui_common.h +++ b/core/embed/rust/rust_ui_common.h @@ -1,7 +1,8 @@ #include "common.h" -void screen_fatal_error_rust(const char* title, const char* msg, - const char* footer); +__attribute__((noreturn)) void error_shutdown_rust(const char* title, + const char* msg, + const char* footer); void screen_boot_stage_2(void); diff --git a/core/embed/rust/src/crypto/mod.rs b/core/embed/rust/src/crypto/mod.rs index ecb5348f67..9b753f9632 100644 --- a/core/embed/rust/src/crypto/mod.rs +++ b/core/embed/rust/src/crypto/mod.rs @@ -1,3 +1,5 @@ +use crate::error::value_error; + pub mod cosi; pub mod ed25519; mod ffi; @@ -16,9 +18,9 @@ pub enum Error { impl From for crate::error::Error { fn from(e: Error) -> Self { match e { - Error::SignatureVerificationFailed => value_error!("Signature verification failed"), - Error::InvalidEncoding => value_error!("Invalid key or signature encoding"), - Error::InvalidParams => value_error!("Invalid cryptographic parameters"), + Error::SignatureVerificationFailed => value_error!(c"Signature verification failed"), + Error::InvalidEncoding => value_error!(c"Invalid key or signature encoding"), + Error::InvalidParams => value_error!(c"Invalid cryptographic parameters"), } } } diff --git a/core/embed/rust/src/debug.rs b/core/embed/rust/src/debug.rs new file mode 100644 index 0000000000..faabf208f6 --- /dev/null +++ b/core/embed/rust/src/debug.rs @@ -0,0 +1,29 @@ +mod unix_ffi { + const STDOUT_FILENO: cty::c_int = 1; + + extern "C" { + pub fn write(fd: cty::c_int, buf: *const u8, count: cty::size_t) -> cty::ssize_t; + } + + pub fn print(to_log: &str) { + unsafe { + write(STDOUT_FILENO, to_log.as_ptr(), to_log.len() as cty::size_t); + } + } +} + +#[cfg(feature = "micropython")] +use crate::micropython::print::print; +#[cfg(not(feature = "micropython"))] +pub use unix_ffi::print; + +pub struct DebugConsole; + +impl ufmt::uWrite for DebugConsole { + type Error = core::convert::Infallible; + + fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { + print(s); + Ok(()) + } +} diff --git a/core/embed/rust/src/error.rs b/core/embed/rust/src/error.rs index 4b2db7d02e..51e59c670f 100644 --- a/core/embed/rust/src/error.rs +++ b/core/embed/rust/src/error.rs @@ -1,5 +1,4 @@ -use core::{convert::Infallible, num::TryFromIntError}; -use cstr_core::CStr; +use core::{convert::Infallible, ffi::CStr, num::TryFromIntError}; #[cfg(feature = "micropython")] use { @@ -27,13 +26,14 @@ pub enum Error { ValueErrorParam(&'static CStr, Obj), } -#[macro_export] macro_rules! value_error { ($msg:expr) => { - $crate::error::Error::ValueError(cstr_core::cstr!($msg)) + $crate::error::Error::ValueError($msg) }; } +pub(crate) use value_error; + #[cfg(feature = "micropython")] impl Error { /// Create an exception instance matching the error code. The result of this diff --git a/core/embed/rust/src/io.rs b/core/embed/rust/src/io.rs index dbef3552e7..a137955dbf 100644 --- a/core/embed/rust/src/io.rs +++ b/core/embed/rust/src/io.rs @@ -1,5 +1,8 @@ use crate::error::Error; +#[cfg(feature = "micropython")] +use crate::micropython::{buffer::get_buffer, gc::Gc, obj::Obj}; + pub struct InputStream<'a> { buf: &'a [u8], pos: usize, @@ -69,3 +72,126 @@ impl<'a> InputStream<'a> { Ok(uint) } } + +#[derive(Copy, Clone)] +pub enum BinaryData<'a> { + Slice(&'a [u8]), + #[cfg(feature = "micropython")] + Object(Obj), + #[cfg(feature = "micropython")] + AllocatedSlice(Gc<[u8]>), +} + +impl<'a> BinaryData<'a> { + /// Returns `true` if the binary data is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Returns a reference to the binary data. + /// + /// This function is used just in the `paint()` functions in + /// UI components, that are going to be deleted after adopting new + /// drawing library for models T and TS3. Do not use this function in new + /// code. + /// + /// # Safety + /// The caller must ensure that the returned slice is not modified by + /// MicroPython. This means (a) discarding the slice before returning + /// to Python, and (b) being careful about calling into Python while + /// the slice is held. + pub unsafe fn data(&self) -> &[u8] { + match self { + Self::Slice(data) => data, + // SAFETY: We expect no existing mutable reference. See safety + // note above. + #[cfg(feature = "micropython")] + Self::Object(obj) => unsafe { unwrap!(get_buffer(*obj)) }, + #[cfg(feature = "micropython")] + Self::AllocatedSlice(data) => data, + } + } + + /// Returns the length of the binary data in bytes. + pub fn len(&self) -> usize { + match self { + Self::Slice(data) => data.len(), + #[cfg(feature = "micropython")] + // SAFETY: We expect no existing mutable reference. + Self::Object(obj) => unsafe { unwrap!(get_buffer(*obj)).len() }, + #[cfg(feature = "micropython")] + Self::AllocatedSlice(data) => data.len(), + } + } + + /// Reads binary data from the source into the buffer. + /// - 'ofs' is the offset in bytes from the start of the binary data. + /// - 'buff' is the buffer to read the data into. + /// + /// Returns the number of bytes read. + pub fn read(&self, ofs: usize, buff: &mut [u8]) -> usize { + match self { + Self::Slice(data) => { + let remaining = data.len().saturating_sub(ofs); + let size = buff.len().min(remaining); + buff[..size].copy_from_slice(&data[ofs..ofs + size]); + size + } + + // SAFETY: We expect no existing mutable reference to `obj`. + #[cfg(feature = "micropython")] + Self::Object(obj) => { + let data = unsafe { unwrap!(get_buffer(*obj)) }; + let remaining = data.len().saturating_sub(ofs); + let size = buff.len().min(remaining); + buff[..size].copy_from_slice(&data[ofs..ofs + size]); + size + } + + #[cfg(feature = "micropython")] + Self::AllocatedSlice(data) => { + let remaining = data.len().saturating_sub(ofs); + let size = buff.len().min(remaining); + buff[..size].copy_from_slice(&data[ofs..ofs + size]); + size + } + } + } +} + +impl<'a> PartialEq for BinaryData<'a> { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::Slice(a), Self::Slice(b)) => a.as_ptr() == b.as_ptr() && a.len() == b.len(), + #[cfg(feature = "micropython")] + (Self::Object(a), Self::Object(b)) => a == b, + #[cfg(feature = "micropython")] + _ => false, + } + } +} + +#[cfg(feature = "micropython")] +impl From> for BinaryData<'static> { + fn from(data: Gc<[u8]>) -> Self { + Self::AllocatedSlice(data) + } +} + +#[cfg(feature = "micropython")] +impl TryFrom for BinaryData<'static> { + type Error = Error; + + fn try_from(obj: Obj) -> Result { + if !obj.is_bytes() { + return Err(Error::TypeError); + } + Ok(Self::Object(obj)) + } +} + +impl<'a> From<&'a [u8]> for BinaryData<'a> { + fn from(data: &'a [u8]) -> Self { + Self::Slice(data) + } +} diff --git a/core/embed/rust/src/lib.rs b/core/embed/rust/src/lib.rs index 3727d38d32..23ed6a215d 100644 --- a/core/embed/rust/src/lib.rs +++ b/core/embed/rust/src/lib.rs @@ -13,31 +13,33 @@ extern crate num_derive; #[macro_use] -mod error; -// use trezorhal for its macros early -#[macro_use] -mod trezorhal; +mod macros; #[cfg(feature = "crypto")] mod crypto; +#[cfg(feature = "debug")] +mod debug; +mod error; mod io; mod maybe_trace; #[cfg(feature = "micropython")] -#[macro_use] mod micropython; #[cfg(feature = "protobuf")] mod protobuf; mod storage; +mod strutil; mod time; #[cfg(feature = "ui_debug")] mod trace; #[cfg(feature = "translations")] -pub mod translations; +mod translations; +mod trezorhal; +// mod ui is `pub` because of the re-export pattern in individual models, which +// would trigger a brickload of "unused symbol" warnings otherwise. +// TODO: maybe get rid of the re-export pattern :shrugs: #[cfg(feature = "ui")] -#[macro_use] pub mod ui; -pub mod strutil; #[cfg(feature = "debug")] #[cfg(not(test))] @@ -48,15 +50,10 @@ pub mod strutil; fn panic_debug(panic_info: &core::panic::PanicInfo) -> ! { // Filling at least the file and line information, if available. // TODO: find out how to display message from panic_info.message() - if let Some(location) = panic_info.location() { - let file = location.file(); - print!(file); - print!(":"); - println!(inttostr!(location.line())); - trezorhal::fatal_error::__fatal_error("", "rs", file, location.line(), ""); + trezorhal::fatal_error::__fatal_error("rs", location.file(), location.line()); } else { - trezorhal::fatal_error::__fatal_error("", "rs", "", 0, ""); + trezorhal::fatal_error::__fatal_error("rs", "", 0); } } @@ -74,7 +71,7 @@ fn panic(_info: &core::panic::PanicInfo) -> ! { // raises a Hard Fault on hardware. // // Otherwise, use `unwrap!` macro from trezorhal. - fatal_error!("", "rs"); + fatal_error!("rs"); } #[cfg(not(target_arch = "arm"))] diff --git a/core/embed/rust/src/macros.rs b/core/embed/rust/src/macros.rs new file mode 100644 index 0000000000..b7addc8614 --- /dev/null +++ b/core/embed/rust/src/macros.rs @@ -0,0 +1,57 @@ +macro_rules! unwrap { + ($e:expr, $msg:expr) => {{ + use $crate::trezorhal::fatal_error::UnwrapOrFatalError; + $e.unwrap_or_fatal_error($msg, file!(), line!()) + }}; + ($expr:expr) => { + unwrap!($expr, "unwrap failed") + }; +} + +macro_rules! ensure { + ($what:expr, $error:expr) => { + if !($what) { + $crate::trezorhal::fatal_error::__fatal_error($error, file!(), line!()); + } + }; +} + +macro_rules! fatal_error { + ($msg:expr) => {{ + $crate::trezorhal::fatal_error::__fatal_error($msg, file!(), line!()); + }}; +} + +// from https://docs.rs/ufmt/latest/ufmt/ +// like `std::format!` it returns a `heapless::String` but uses `uwrite!` +// instead of `write!` +macro_rules! uformat { + // IMPORTANT use `tt` fragments instead of `expr` fragments (i.e. `$($exprs:expr),*`) + (@$type:ty, $($tt:tt)*) => {{ + let mut s = <$type>::new(); + unwrap!(ufmt::uwrite!(&mut s, $($tt)*)); + s + }}; + (len:$len:expr, $($tt:tt)*) => { + uformat!(@heapless::String::<$len>, $($tt)*) + }; + ($($tt:tt)*) => { + uformat!(@crate::strutil::ShortString, $($tt)*) + }; +} + +#[allow(unused_macros)] // Should be used only for debugging purposes +macro_rules! dbg_print { + ($($args:tt)*) => { + #[cfg(feature = "debug")] + ufmt::uwrite!($crate::debug::DebugConsole, $($args)*).ok(); + } +} + +#[allow(unused_macros)] // Should be used only for debugging purposes +macro_rules! dbg_println { + ($($args:tt)*) => { + #[cfg(feature = "debug")] + ufmt::uwriteln!($crate::debug::DebugConsole, $($args)*).ok(); + } +} diff --git a/core/embed/rust/src/micropython/buffer.rs b/core/embed/rust/src/micropython/buffer.rs index ee92471114..456d131f58 100644 --- a/core/embed/rust/src/micropython/buffer.rs +++ b/core/embed/rust/src/micropython/buffer.rs @@ -20,7 +20,7 @@ use super::ffi; /// The `off` field represents offset from the `ptr` and allows us to do /// substring slices while keeping the head pointer as required by GC. #[repr(C)] -#[derive(Debug, Copy, Clone)] +#[derive(Copy, Clone)] pub struct StrBuffer { ptr: *const u8, len: u16, @@ -165,6 +165,19 @@ impl From<&'static str> for StrBuffer { } } +#[cfg(feature = "debug")] +impl ufmt::uDebug for StrBuffer { + fn fmt(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error> + where + W: ufmt::uWrite + ?Sized, + { + f.write_str("StrBuffer(")?; + f.write_str(self.as_ref())?; + f.write_str(")")?; + Ok(()) + } +} + fn get_buffer_info(obj: Obj, flags: u32) -> Result { let mut bufinfo = ffi::mp_buffer_info_t { buf: ptr::null_mut(), diff --git a/core/embed/rust/src/micropython/gc.rs b/core/embed/rust/src/micropython/gc.rs index 3c0fe8e05c..8a9d103498 100644 --- a/core/embed/rust/src/micropython/gc.rs +++ b/core/embed/rust/src/micropython/gc.rs @@ -1,6 +1,6 @@ use core::{ alloc::Layout, - ops::Deref, + ops::{Deref, DerefMut}, ptr::{self, NonNull}, }; @@ -9,16 +9,34 @@ use crate::error::Error; use super::ffi; /// A pointer type for values on the garbage-collected heap. -/// -/// Although a garbage-collected pointer type technically should implement -/// `Copy` and `Clone`, we avoid doing this until proven necessary. pub struct Gc(NonNull); +impl Clone for Gc { + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Gc {} + impl Gc { /// Allocate memory on the heap managed by the MicroPython garbage collector - /// and then place `v` into it. `v` will _not_ get its destructor called. - pub fn new(v: T) -> Result { + /// and then place `v` into it. + /// + /// `flags` can be an int value built out of constants in the ffi module. + /// The current MicroPython only supports GC_ALLOC_FLAG_HAS_FINALISER, which + /// will cause the __del__ method to be called when the object is + /// garbage collected. + /// + /// SAFETY: + /// Flag GC_ALLOC_FLAG_HAS_FINALISER can only be used with Python objects + /// that have a base as their first element + unsafe fn alloc(v: T, flags: u32) -> Result { let layout = Layout::for_value(&v); + debug_assert!( + layout.size() > 0, + "Zero-sized allocations are not supported" + ); // TODO: Assert that `layout.align()` is the same as the GC alignment. // SAFETY: // - Unfortunately we cannot respect `layout.align()` as MicroPython GC does @@ -27,7 +45,7 @@ impl Gc { // or the MicroPython heap. // EXCEPTION: Returns null instead of raising. unsafe { - let raw = ffi::gc_alloc(layout.size(), 0); + let raw = ffi::gc_alloc(layout.size(), flags); if raw.is_null() { return Err(Error::AllocationFailed); } @@ -36,6 +54,30 @@ impl Gc { Ok(Self::from_raw(typed)) } } + + /// Allocate memory on the heap managed by the MicroPython garbage collector + /// and then place `v` into it. `v` will _not_ get its destructor called. + pub fn new(v: T) -> Result { + unsafe { + // SAFETY: No flag is used + Self::alloc(v, 0) + } + } + + /// Allocate memory on the heap managed by the MicroPython garbage + /// collector, place `v` into it, and register for finalisation. + /// + /// `v` will **not** get its destructor called automatically! However, if + /// `v` is a Python-style object (has a base as its first field), and + /// has a `__del__` method, it will be called when the object is garbage + /// collected. You can use this to implement custom finalisation, in + /// which you can, e.g., invoke the Drop implementation. + /// SAFETY: + /// Can only be used with Python objects that have a base as their + /// first element + pub unsafe fn new_with_custom_finaliser(v: T) -> Result { + unsafe { Self::alloc(v, ffi::GC_ALLOC_FLAG_HAS_FINALISER) } + } } impl Gc<[T]> { @@ -100,6 +142,20 @@ impl Gc { // a mutable reference. unsafe { this.0.as_mut() } } + + /// Return a immutable reference to the value. + /// + /// # Safety + /// + /// `Gc` values can originate in the MicroPython interpreter, and these can + /// be both shared and mutable. Before calling this function, you have to + /// ensure that `this` does not get externally mutated and nobody + /// holds a mutable reference. + pub unsafe fn as_ref(this: &Self) -> &T { + // SAFETY: The caller must guarantee that `this` meets all the requirements for + // a immutable reference. + unsafe { this.0.as_ref() } + } } impl Deref for Gc { @@ -109,3 +165,225 @@ impl Deref for Gc { unsafe { self.0.as_ref() } } } + +/// Box-like allocation on the GC heap. +/// +/// Values allocated using GcBox are guaranteed to be only owned by that +/// particular GcBox instance. This makes them safe to mutate, and they run +/// destructors when dropped. +/// +/// Suitable for use in cases where you would normally use Rust's native Box +/// type -- i.e., typically for storing sub-values in a struct, possibly also +/// for returning values from functions. +/// +/// While general unsizing is not available, you can use the `coerce!` macro to +/// safely cast the box to a trait object. +/// +/// # Safety and usage notes +/// +/// One caveat of using GcBox is that it still always needs to be visible to the +/// GC -- that is, stored in a struct which is allocated on the GC heap, on the +/// call stack, or reachable from one of the GC roots. +/// +/// Specifically, it is generally unsafe to store a GcBox in a global variable. +/// +/// When a GcBox is stored in a struct, which itself is allocated via raw GC, +/// the containing struct might get GC'd, which will cause GcBox not to get +/// dropped, which in turn will prevent GcBox's contents from getting dropped. +pub struct GcBox(Gc); + +impl GcBox { + /// Allocate memory on the heap managed by the MicroPython GC and then place + /// `value` into it. + /// + /// `value` _will_ get its Drop implementation called when the GcBox is + /// dropped. + pub fn new(value: T) -> Result { + Ok(Self(Gc::new(value)?)) + } +} + +impl GcBox { + /// Leak contents of the box as a pointer. + /// + /// # Safety + /// + /// The value will not be dropped. If necessary, the caller is responsible + /// for dropping it manually, e.g., via `ptr::drop_in_place`. + pub fn into_raw(this: Self) -> *mut T { + let result = Gc::into_raw(this.0); + core::mem::forget(this); + result + } + + /// Construct a `GcBox` from a raw pointer. + /// + /// # Safety + /// + /// This is only safe for pointers _allocated on the MicroPython GC heap_ + /// via `gc_alloc()`. Specifically, unlike `Gc::from_raw`, it is unsafe + /// to construct a GcBox from ROM values, even those that are trackable + /// by the GC. + /// + /// This is because the Drop implementation of GcBox calls `gc_free()` on + /// the pointer. + /// + /// In addition, the caller must ensure that it is safe to apply box-like + /// semantics to the value, namely that: + /// * nobody else has the pointer to the value, so that it is safe to + /// create mutable references to it + /// * the value is going to be dropped when the GcBox is dropped. + pub unsafe fn from_raw(ptr: *mut T) -> Self { + // SAFETY: just a wrapper around Gc::from_raw + Self(unsafe { Gc::from_raw(ptr) }) + } + + /// Leak contents of the box as a regular Gc allocation. + /// + /// This gives up the unique ownership. It is no longer possible to safely + /// mutably borrow the value, and its destructor will not be called when + /// it is dropped. In exchange, it is possible to return Gc instance to + /// MicroPython. + pub fn leak(self) -> Gc { + let inner = self.0; + core::mem::forget(self); + inner + } +} + +/// Type-cast GcBox contents to a `dyn Trait` object. +macro_rules! coerce { + ($t:path, $v:expr) => { + // SAFETY: we are just re-wrapping the pointer, so all safety requirements + // of `GcBox::from_raw` are upheld. + // Rust type system will not allow us to cast to a trait object that is not + // implemented by the type. + unsafe { GcBox::from_raw(GcBox::into_raw($v) as *mut dyn $t) } + }; +} + +pub(crate) use coerce; + +impl Deref for GcBox { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + +impl DerefMut for GcBox { + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: We are the sole owner of the allocated value, and we are borrowed + // mutably. + unsafe { Gc::as_mut(&mut self.0) } + } +} + +impl Drop for GcBox { + fn drop(&mut self) { + let ptr = Gc::into_raw(self.0); + // SAFETY: We are the sole owner of the allocated value, and we are being + // dropped. + unsafe { + ptr::drop_in_place(ptr); + ffi::gc_free(ptr.cast()); + } + } +} + +#[cfg(test)] +mod test { + use core::cell::Cell; + + use crate::micropython::testutil::mpy_init; + + use super::*; + + struct SignalDrop<'a>(&'a Cell); + + impl Drop for SignalDrop<'_> { + fn drop(&mut self) { + self.0.set(true); + } + } + + trait Foo { + fn foo(&self) -> i32; + } + + impl Foo for SignalDrop<'_> { + fn foo(&self) -> i32 { + 42 + } + } + + #[test] + fn gc_nodrop() { + unsafe { mpy_init() }; + + let drop_signalled = Cell::new(false); + { + let _gc = Gc::new(SignalDrop(&drop_signalled)).unwrap(); + } + assert!(!drop_signalled.get()); + } + + #[test] + fn gcbox_drop() { + unsafe { mpy_init() }; + + let drop_signalled = Cell::new(false); + { + let _gcbox = GcBox::new(SignalDrop(&drop_signalled)).unwrap(); + } + assert!(drop_signalled.get()); + } + + #[test] + fn gc_raw_roundtrip() { + unsafe { mpy_init() }; + + let gc = Gc::new(42).unwrap(); + let ptr = Gc::into_raw(gc); + let wrapped = unsafe { Gc::from_raw(ptr) }; + let retrieved = Gc::into_raw(wrapped); + assert_eq!(ptr, retrieved); + } + + #[test] + fn gcbox_raw_roundtrip() { + unsafe { mpy_init() }; + + let drop_signalled = Cell::new(false); + + { + let gcbox = GcBox::new(SignalDrop(&drop_signalled)).unwrap(); + assert!(!drop_signalled.get()); + let ptr = GcBox::into_raw(gcbox); + assert!(!drop_signalled.get()); + let wrapped = unsafe { GcBox::from_raw(ptr) }; + assert!(!drop_signalled.get()); + let retrieved = GcBox::into_raw(wrapped); + assert!(!drop_signalled.get()); + assert_eq!(ptr, retrieved); + + let _rewrapped = unsafe { GcBox::from_raw(ptr) }; + } + assert!(drop_signalled.get()); + } + + #[test] + fn test_coerce() { + unsafe { mpy_init() }; + + let drop_signalled = Cell::new(false); + { + let gcbox = GcBox::new(SignalDrop(&drop_signalled)).unwrap(); + let coerced: GcBox = coerce!(Foo, gcbox); + assert!(!drop_signalled.get()); + assert_eq!(coerced.foo(), 42); + } + assert!(drop_signalled.get()); + } +} diff --git a/core/embed/rust/src/micropython/iter.rs b/core/embed/rust/src/micropython/iter.rs index afbfcf9ed6..fbc3220466 100644 --- a/core/embed/rust/src/micropython/iter.rs +++ b/core/embed/rust/src/micropython/iter.rs @@ -87,7 +87,7 @@ impl<'a> Iterator for Iter<'a> { self.iter_buf.caught_exception = exc; None } - Err(_) => panic!("unexpected error"), + Err(_) => fatal_error!("Unexpected error"), Ok(item) if item == Obj::const_stop_iteration() => { self.finished = true; None diff --git a/core/embed/rust/src/micropython/list.rs b/core/embed/rust/src/micropython/list.rs index 42da263139..3073adbc72 100644 --- a/core/embed/rust/src/micropython/list.rs +++ b/core/embed/rust/src/micropython/list.rs @@ -2,7 +2,12 @@ use core::{convert::TryFrom, ptr}; use crate::error::Error; -use super::{ffi, gc::Gc, obj::Obj, runtime::catch_exception}; +use super::{ + ffi, + gc::{Gc, GcBox}, + obj::Obj, + runtime::catch_exception, +}; pub type List = ffi::mp_obj_list_t; @@ -17,29 +22,29 @@ impl List { }) } - pub fn with_capacity(capacity: usize) -> Result, Error> { + pub fn with_capacity(capacity: usize) -> Result, Error> { // EXCEPTION: Will raise if allocation fails. catch_exception(|| unsafe { let list = ffi::mp_obj_new_list(capacity, ptr::null_mut()); // By default, the new list will have its len set to n. We want to preallocate // to a specific size and then use append() to add items, so we reset len to 0. ffi::mp_obj_list_set_len(list, 0); - Gc::from_raw(list.as_ptr().cast()) + // SAFETY: list is freshly allocated so we are still its unique owner. + GcBox::from_raw(list.as_ptr().cast()) }) } - pub fn from_iter(iter: impl Iterator) -> Result, Error> + pub fn from_iter(iter: impl Iterator) -> Result, Error> where T: TryInto, Error: From, { let max_size = iter.size_hint().1.unwrap_or(0); - let mut gc_list = List::with_capacity(max_size)?; - let list = unsafe { Gc::as_mut(&mut gc_list) }; + let mut list = List::with_capacity(max_size)?; for value in iter { list.append(value.try_into()?)?; } - Ok(gc_list) + Ok(list) } // Internal helper to get the `Obj` variant of this. @@ -155,7 +160,7 @@ mod tests { // create an upy list of 5 elements let vec: Vec = (0..5).collect(); - let list: Obj = List::from_iter(vec.iter().copied()).unwrap().into(); + let list: Obj = List::from_iter(vec.iter().copied()).unwrap().leak().into(); // collect the elements into a Vec of maximum length 10, through an iterator let retrieved_vec: Vec = IterBuf::new() @@ -181,8 +186,7 @@ mod tests { unsafe { mpy_init() }; let vec: Vec = (0..17).collect(); - let mut gc_list = List::from_iter(vec.iter().copied()).unwrap(); - let list = unsafe { Gc::as_mut(&mut gc_list) }; + let mut list = List::from_iter(vec.iter().copied()).unwrap(); for (i, value) in vec.iter().copied().enumerate() { assert_eq!( @@ -197,7 +201,7 @@ mod tests { } let retrieved_vec: Vec = IterBuf::new() - .try_iterate(gc_list.into()) + .try_iterate(list.leak().into()) .unwrap() .map(TryInto::try_into) .collect::, Error>>() @@ -229,7 +233,7 @@ mod tests { let vec: Vec = (0..5).collect(); let mut list = List::from_iter(vec.iter().copied()).unwrap(); - let slice = unsafe { Gc::as_mut(&mut list).as_mut_slice() }; + let slice = unsafe { list.as_mut_slice() }; assert_eq!(slice.len(), vec.len()); assert_eq!(vec[0], TryInto::::try_into(slice[0]).unwrap()); @@ -238,7 +242,7 @@ mod tests { } let retrieved_vec: Vec = IterBuf::new() - .try_iterate(list.into()) + .try_iterate(list.leak().into()) .unwrap() .map(TryInto::try_into) .collect::, Error>>() diff --git a/core/embed/rust/src/micropython/macros.rs b/core/embed/rust/src/micropython/macros.rs index daab06d6f2..c058bcb429 100644 --- a/core/embed/rust/src/micropython/macros.rs +++ b/core/embed/rust/src/micropython/macros.rs @@ -1,74 +1,49 @@ -/// Create an object for an exported function taking no arguments. -macro_rules! obj_fn_0 { - ($f:expr) => {{ +macro_rules! _obj_fn_make_fixed { + ($type:ident, $member:ident, $f:expr) => {{ #[allow(unused_unsafe)] unsafe { use $crate::micropython::ffi; ffi::mp_obj_fun_builtin_fixed_t { base: ffi::mp_obj_base_t { - type_: &ffi::mp_type_fun_builtin_0, + type_: &$crate::micropython::ffi::$type, }, - fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { _0: Some($f) }, + fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { $member: Some($f) }, } } }}; } +/// Create an object for an exported function taking no arguments. +macro_rules! obj_fn_0 { + ($f:expr) => { + crate::micropython::macros::_obj_fn_make_fixed!(mp_type_fun_builtin_0, _0, $f) + }; +} + /// Create an object for an exported function taking 1 arg. macro_rules! obj_fn_1 { - ($f:expr) => {{ - #[allow(unused_unsafe)] - unsafe { - use $crate::micropython::ffi; - - ffi::mp_obj_fun_builtin_fixed_t { - base: ffi::mp_obj_base_t { - type_: &ffi::mp_type_fun_builtin_1, - }, - fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { _1: Some($f) }, - } - } - }}; + ($f:expr) => { + crate::micropython::macros::_obj_fn_make_fixed!(mp_type_fun_builtin_1, _1, $f) + }; } /// Create an object for an exported function taking 2 args. macro_rules! obj_fn_2 { - ($f:expr) => {{ - #[allow(unused_unsafe)] - unsafe { - use $crate::micropython::ffi; - - ffi::mp_obj_fun_builtin_fixed_t { - base: ffi::mp_obj_base_t { - type_: &ffi::mp_type_fun_builtin_2, - }, - fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { _2: Some($f) }, - } - } - }}; + ($f:expr) => { + crate::micropython::macros::_obj_fn_make_fixed!(mp_type_fun_builtin_2, _2, $f) + }; } /// Create an object for an exported function taking 3 args. macro_rules! obj_fn_3 { - ($f:expr) => {{ - #[allow(unused_unsafe)] - unsafe { - use $crate::micropython::ffi; - - ffi::mp_obj_fun_builtin_fixed_t { - base: ffi::mp_obj_base_t { - type_: &ffi::mp_type_fun_builtin_3, - }, - fun: ffi::_mp_obj_fun_builtin_fixed_t__bindgen_ty_1 { _3: Some($f) }, - } - } - }}; + ($f:expr) => { + crate::micropython::macros::_obj_fn_make_fixed!(mp_type_fun_builtin_3, _3, $f) + }; } -/// Create an object for an exported function taking a variable number of args. -macro_rules! obj_fn_var { - ($min:expr, $max:expr, $f:expr) => {{ +macro_rules! _obj_fn_make_var { + ($min:expr, $max:expr, takes_kw: $takes_kw:expr, $var_or_kw:ident: $f:expr) => {{ #[allow(unused_unsafe)] unsafe { use $crate::micropython::ffi; @@ -77,29 +52,28 @@ macro_rules! obj_fn_var { base: ffi::mp_obj_base_t { type_: &ffi::mp_type_fun_builtin_var, }, - sig: ($min << 17u32) | ($max << 1u32) | 0, // min, max, takes_kw - fun: ffi::_mp_obj_fun_builtin_var_t__bindgen_ty_1 { var: Some($f) }, + sig: ($min << 17u32) | ($max << 1u32) | $takes_kw, + fun: ffi::_mp_obj_fun_builtin_var_t__bindgen_ty_1 { + $var_or_kw: Some($f), + }, } } }}; } +/// Create an object for an exported function taking a variable number of args +/// between min and max +macro_rules! obj_fn_var { + ($min:expr, $max:expr, $f:expr) => { + crate::micropython::macros::_obj_fn_make_var!($min, $max, takes_kw:0, var:$f) + }; +} + /// Create an object for an exported function taking key-value args. macro_rules! obj_fn_kw { - ($min:expr, $f:expr) => {{ - #[allow(unused_unsafe)] - unsafe { - use $crate::micropython::ffi; - - ffi::mp_obj_fun_builtin_var_t { - base: ffi::mp_obj_base_t { - type_: &ffi::mp_type_fun_builtin_var, - }, - sig: ($min << 17u32) | (0xffff << 1u32) | 1, // min, max, takes_kw - fun: ffi::_mp_obj_fun_builtin_var_t__bindgen_ty_1 { kw: Some($f) }, - } - } - }}; + ($min:expr, $f:expr) => { + crate::micropython::macros::_obj_fn_make_var!($min, 0xffff, takes_kw:1, kw:$f) + }; } /// Construct fixed static const `Map` from `key` => `val` pairs. @@ -261,26 +235,18 @@ macro_rules! attr_tuple { }); } -/// Print arbitrary amounts of slices into a terminal. -/// Does not include a newline at the end. -/// Does not do anything when not in debugging mode. -#[allow(unused_macros)] // Should be used only for debugging purposes -macro_rules! print { - ($($string:expr),+) => { - #[cfg(feature = "debug")] - { - $(crate::micropython::print::print($string);)+ - } - } -} - -/// Print arbitrary amounts of slices into a terminal. -/// Includes a newline at the end. -/// Does not do anything when not in debugging mode. -#[allow(unused_macros)] // Should be used only for debugging purposes -macro_rules! println { - ($($string:expr),+) => { - // Just delegating to print! and adding a newline - print!($($string),+, "\n"); - } -} +// required because they are used in expansion of macros below +pub(crate) use _obj_fn_make_fixed; +pub(crate) use _obj_fn_make_var; + +pub(crate) use attr_tuple; +pub(crate) use obj_dict; +pub(crate) use obj_fn_0; +pub(crate) use obj_fn_1; +pub(crate) use obj_fn_2; +pub(crate) use obj_fn_3; +pub(crate) use obj_fn_kw; +pub(crate) use obj_fn_var; +pub(crate) use obj_map; +pub(crate) use obj_module; +pub(crate) use obj_type; diff --git a/core/embed/rust/src/micropython/obj.rs b/core/embed/rust/src/micropython/obj.rs index dd0913223d..38e75d00b8 100644 --- a/core/embed/rust/src/micropython/obj.rs +++ b/core/embed/rust/src/micropython/obj.rs @@ -1,6 +1,7 @@ -use core::convert::{TryFrom, TryInto}; - -use cstr_core::CStr; +use core::{ + convert::{TryFrom, TryInto}, + ffi::CStr, +}; use crate::error::Error; @@ -290,7 +291,7 @@ impl TryFrom<&'static CStr> for Obj { // SAFETY: // - `CStr` is guaranteed to be null-terminated UTF-8. // - the argument is static so it will remain valid for the lifetime of result. - let obj = unsafe { ffi::trezor_obj_str_from_rom_text(val.as_ptr()) }; + let obj = unsafe { ffi::trezor_obj_str_from_rom_text(val.as_ptr() as _) }; if obj.is_null() { Err(Error::AllocationFailed) } else { diff --git a/core/embed/rust/src/micropython/runtime.rs b/core/embed/rust/src/micropython/runtime.rs index c33bb40b52..a2dced61d4 100644 --- a/core/embed/rust/src/micropython/runtime.rs +++ b/core/embed/rust/src/micropython/runtime.rs @@ -17,7 +17,6 @@ pub unsafe fn raise_exception(err: Error) -> ! { // (err.into_obj() should return the right thing) ffi::nlr_jump(err.into_obj().as_ptr()); } - panic!(); } /// Execute `func` while catching MicroPython exceptions. Returns `Ok` in the diff --git a/core/embed/rust/src/micropython/util.rs b/core/embed/rust/src/micropython/util.rs index a8f337cfeb..07b40bfb6f 100644 --- a/core/embed/rust/src/micropython/util.rs +++ b/core/embed/rust/src/micropython/util.rs @@ -10,7 +10,7 @@ use super::{ qstr::Qstr, runtime::{catch_exception, raise_exception}, }; -use crate::error::Error; +use crate::error::{value_error, Error}; /// Perform a call and convert errors into a raised MicroPython exception. /// Should only called when returning from Rust to C. See `raise_exception` for @@ -133,7 +133,7 @@ where let vec: Vec = iter_into_vec(iterable)?; // Returns error if array.len() != N vec.into_array() - .map_err(|_| value_error!("Invalid iterable length")) + .map_err(|_| value_error!(c"Invalid iterable length")) } pub fn iter_into_vec(iterable: Obj) -> Result, Error> @@ -144,7 +144,7 @@ where let mut vec = Vec::::new(); for item in IterBuf::new().try_iterate(iterable)? { vec.push(item.try_into()?) - .map_err(|_| value_error!("Invalid iterable length"))?; + .map_err(|_| value_error!(c"Invalid iterable length"))?; } Ok(vec) } diff --git a/core/embed/rust/src/protobuf/error.rs b/core/embed/rust/src/protobuf/error.rs index 90cf2ee380..23ea2ae86b 100644 --- a/core/embed/rust/src/protobuf/error.rs +++ b/core/embed/rust/src/protobuf/error.rs @@ -1,23 +1,24 @@ -use cstr_core::cstr; - -use crate::{error::Error, micropython::qstr::Qstr}; +use crate::{ + error::{value_error, Error}, + micropython::qstr::Qstr, +}; pub const fn experimental_not_enabled() -> Error { - value_error!("Experimental features are disabled.") + value_error!(c"Experimental features are disabled.") } pub const fn unknown_field_type() -> Error { - value_error!("Unknown field type.") + value_error!(c"Unknown field type.") } pub fn missing_required_field(field: Qstr) -> Error { - Error::ValueErrorParam(cstr!("Missing required field."), field.into()) + Error::ValueErrorParam(c"Missing required field.", field.into()) } pub fn invalid_value(field: Qstr) -> Error { - Error::ValueErrorParam(cstr!("Invalid value for field."), field.into()) + Error::ValueErrorParam(c"Invalid value for field.", field.into()) } pub const fn end_of_buffer() -> Error { - value_error!("End of buffer.") + value_error!(c"End of buffer.") } diff --git a/core/embed/rust/src/protobuf/obj.rs b/core/embed/rust/src/protobuf/obj.rs index 5efecf4510..7b4c69033c 100644 --- a/core/embed/rust/src/protobuf/obj.rs +++ b/core/embed/rust/src/protobuf/obj.rs @@ -6,6 +6,7 @@ use crate::{ dict::Dict, ffi, gc::Gc, + macros::{obj_fn_1, obj_fn_2, obj_fn_3, obj_module, obj_type}, map::Map, module::Module, obj::{Obj, ObjBase}, diff --git a/core/embed/rust/src/storage/mod.rs b/core/embed/rust/src/storage/mod.rs index 96eab3df72..bd6e6aec09 100644 --- a/core/embed/rust/src/storage/mod.rs +++ b/core/embed/rust/src/storage/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] -use crate::trezorhal::storage::{get, get_length, StorageResult}; +use crate::trezorhal::storage::{self, StorageResult}; pub const HOMESCREEN_MAX_SIZE: usize = 16384; @@ -36,14 +36,30 @@ const INITIALIZED: u16 = FLAG_PUBLIC | APP_DEVICE | 0x0013; const SAFETY_CHECK_LEVEL: u16 = APP_DEVICE | 0x0014; const EXPERIMENTAL_FEATURES: u16 = APP_DEVICE | 0x0015; const HIDE_PASSPHRASE_FROM_HOST: u16 = APP_DEVICE | 0x0016; +const SLIP39_EXTENDABLE: u16 = APP_DEVICE | 0x0017; +const BRIGHTNESS: u16 = FLAG_PUBLIC | APP_DEVICE | 0x0019; pub fn get_avatar_len() -> StorageResult { - get_length(HOMESCREEN) + storage::get_length(HOMESCREEN) } pub fn load_avatar(dest: &mut [u8]) -> StorageResult<()> { let dest_len = dest.len(); - let result = get(HOMESCREEN, dest)?; + let result = storage::get(HOMESCREEN, dest)?; ensure!(dest_len == result.len(), "Internal error in load_avatar"); Ok(()) } + +pub fn get_brightness() -> StorageResult { + let mut dest: [u8; 1] = [0; 1]; + let res = storage::get(BRIGHTNESS, &mut dest); + match res { + Ok(_) => Ok(dest[0]), + Err(e) => Err(e), + } +} + +pub fn set_brightness(value: u8) -> StorageResult<()> { + let value = [value]; + storage::set(BRIGHTNESS, &value) +} diff --git a/core/embed/rust/src/strutil.rs b/core/embed/rust/src/strutil.rs index 3210ddc4a1..49e3e2cd1e 100644 --- a/core/embed/rust/src/strutil.rs +++ b/core/embed/rust/src/strutil.rs @@ -9,19 +9,6 @@ use crate::micropython::{buffer::StrBuffer, obj::Obj}; #[cfg(feature = "translations")] use crate::translations::TR; -/// Trait for internal representation of strings. This is a legacy crutch before -/// we fully transition to `TString`. For now, it allows some manner of -/// compatibility between `&str` and `StrBuffer`. Implies the following -/// operations: -/// - dereference into a short-lived `&str` reference (AsRef) (probably not -/// strictly necessary anymore) -/// - create a new string from a string literal (From<&'static str>) -/// - infallibly convert into a `TString` (Into>), which is -/// then used for other operations. -pub trait StringType: AsRef + From<&'static str> + Into> {} - -impl StringType for T where T: AsRef + From<&'static str> + Into> {} - /// Unified-length String type, long enough for most simple use-cases. pub type ShortString = String<50>; @@ -195,3 +182,43 @@ impl<'a, 'b> PartialEq> for TString<'b> { } impl Eq for TString<'_> {} + +impl ufmt::uDisplay for TString<'_> { + fn fmt(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error> + where + W: ufmt::uWrite + ?Sized, + { + self.map(|s| f.write_str(s)) + } +} + +#[cfg(feature = "debug")] +impl ufmt::uDebug for TString<'_> { + fn fmt(&self, f: &mut ufmt::Formatter<'_, W>) -> Result<(), W::Error> + where + W: ufmt::uWrite + ?Sized, + { + match self { + #[cfg(feature = "micropython")] + TString::Allocated(buf) => { + f.write_str("Allocated(")?; + buf.fmt(f)?; + f.write_str(")")?; + } + #[cfg(feature = "translations")] + TString::Translation { tr, offset } => { + f.write_str("Translation(")?; + tr.fmt(f)?; + f.write_str(", ")?; + offset.fmt(f)?; + f.write_str(")")?; + } + TString::Str(s) => { + f.write_str("Str(")?; + f.write_str(s)?; + f.write_str(")")?; + } + } + Ok(()) + } +} diff --git a/core/embed/rust/src/time.rs b/core/embed/rust/src/time.rs index 726d7a7e16..abdb8bedf0 100644 --- a/core/embed/rust/src/time.rs +++ b/core/embed/rust/src/time.rs @@ -7,7 +7,7 @@ use crate::trezorhal::time; const MILLIS_PER_SEC: u32 = 1000; -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct Duration { millis: u32, } @@ -148,6 +148,76 @@ impl Ord for Instant { } } +/// A stopwatch is a utility designed for measuring the amount of time +/// that elapses between its start and stop points. It can be used in various +/// situations - animation timing, event timing, testing and debugging. +#[derive(Clone)] +pub enum Stopwatch { + Stopped(Duration), + Running(Instant), +} + +impl Default for Stopwatch { + /// Returns a new sopteed stopwatch by default. + fn default() -> Self { + Self::new_stopped() + } +} + +impl Stopwatch { + /// Creates a new stopped stopwatch with duration of zero + pub fn new_stopped() -> Self { + Self::Stopped(Duration::ZERO) + } + + /// Creates a new started stopwatch that starts + /// at the current instant. + pub fn new_started() -> Self { + Self::Running(Instant::now()) + } + + /// Starts or restarts the stopwatch. + /// + /// If the stopwatch is already running, it restarts, setting + /// the elapsed time to zero. + pub fn start(&mut self) { + *self = Self::Running(Instant::now()); + } + + /// Stops the stopwatch. + /// + /// When stopped, the `elapsed()` method will return the total + /// duration for which the stopwatch was running. + pub fn stop(&mut self) { + *self = Self::Stopped(self.elapsed()); + } + + /// Returns the elapsed duration since the stopwatch was last started. + /// + /// If the stopwatch is running, it calculates the time from the last + /// start instant to the current instant. + pub fn elapsed(&self) -> Duration { + match *self { + Self::Stopped(duration) => duration, + Self::Running(time) => Instant::now().checked_duration_since(time).unwrap(), + } + } + + /// Returns `true` if the stopwatch is currently running. + pub fn is_running(&self) -> bool { + matches!(*self, Self::Running(_)) + } + + /// Checks if the stopwatch is running and whether the elapsed + /// time since the last start is less than or equal to a specified limit. + pub fn is_running_within(&self, limit: Duration) -> bool { + match *self { + Self::Stopped(_) => false, + Self::Running(_) => self.elapsed() <= limit, + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -160,4 +230,54 @@ mod tests { assert_eq!(later, Instant { millis: 0 }); assert!(earlier < later); } + + #[test] + fn stopwatch_builds_correctly() { + let sw = Stopwatch::new_started(); + assert!(sw.is_running()); + + let sw = Stopwatch::new_stopped(); + assert!(!sw.is_running()); + + let sw: Stopwatch = Default::default(); + assert!(!sw.is_running()); + } + + fn wait(duration: Duration) { + let origin = Instant::now(); + while Instant::now().checked_duration_since(origin).unwrap() < duration {} + } + + #[test] + fn stopwatch_starts_correcly() { + let mut sw = Stopwatch::new_stopped(); + assert!(!sw.is_running()); + + sw.start(); + assert!(sw.is_running()); + + wait(Duration::from_millis(10)); + assert!(sw.elapsed() >= Duration::from_millis(10)); + assert!(!sw.is_running_within(Duration::from_millis(5))); + assert!(sw.is_running_within(Duration::from_millis(10000))); + } + + #[test] + fn stopwatch_stops_correctly() { + let mut sw = Stopwatch::new_started(); + assert!(sw.is_running()); + + wait(Duration::from_millis(10)); + + sw.stop(); + assert!(!sw.is_running()); + + let elapsed = sw.elapsed(); + assert!(elapsed >= Duration::from_millis(10)); + + wait(Duration::from_millis(10)); + assert!(sw.elapsed() == elapsed); + assert!(!sw.is_running_within(Duration::from_millis(5))); + assert!(!sw.is_running_within(Duration::from_millis(10000))); + } } diff --git a/core/embed/rust/src/translations/blob.rs b/core/embed/rust/src/translations/blob.rs index 3ba42610ba..422259359c 100644 --- a/core/embed/rust/src/translations/blob.rs +++ b/core/embed/rust/src/translations/blob.rs @@ -2,7 +2,7 @@ use core::{mem, str}; use crate::{ crypto::{cosi, ed25519, merkle::merkle_root, sha256}, - error::Error, + error::{value_error, Error}, io::InputStream, }; @@ -19,7 +19,7 @@ const SIGNATURE_THRESHOLD: u8 = 2; // should be max 1. const MAX_TABLE_PADDING: usize = 3; -const INVALID_TRANSLATIONS_BLOB: Error = value_error!("Invalid translations blob"); +const INVALID_TRANSLATIONS_BLOB: Error = value_error!(c"Invalid translations blob"); #[repr(packed)] struct OffsetEntry { @@ -145,7 +145,7 @@ impl<'a> Translations<'a> { let remaining = blob_reader.rest(); if !remaining.iter().all(|&b| b == EMPTY_BYTE) { // TODO optimize to quadwords? - return Err(value_error!("Trailing data in translations blob")); + return Err(value_error!(c"Trailing data in translations blob")); } let payload_bytes = payload_reader.rest(); @@ -337,7 +337,7 @@ impl<'a> TranslationsHeader<'a> { let model = read_fixedsize_str(&mut header_reader, 4)?; if model != crate::trezorhal::model::INTERNAL_NAME { - return Err(value_error!("Wrong Trezor model")); + return Err(value_error!(c"Wrong Trezor model")); } let version_bytes = header_reader.read(4)?; @@ -405,6 +405,7 @@ impl<'a> TranslationsHeader<'a> { } pub fn verify(&self) -> Result<(), Error> { + #[allow(unused_mut)] let mut result = self.verify_with_keys(&public_keys::PUBLIC_KEYS); #[cfg(feature = "debug")] if result.is_err() { diff --git a/core/embed/rust/src/translations/flash.rs b/core/embed/rust/src/translations/flash.rs index 3a7387ad1a..238e41d717 100644 --- a/core/embed/rust/src/translations/flash.rs +++ b/core/embed/rust/src/translations/flash.rs @@ -1,6 +1,9 @@ use spin::{RwLock, RwLockReadGuard}; -use crate::{error::Error, trezorhal::translations}; +use crate::{ + error::{value_error, Error}, + trezorhal::translations, +}; use super::blob::Translations; @@ -15,7 +18,7 @@ pub fn erase() -> Result<(), Error> { let blob = unwrap!(TRANSLATIONS_ON_FLASH.try_write()); { if blob.is_some() { - return Err(value_error!("Translations blob already set")); + return Err(value_error!(c"Translations blob already set")); } // SAFETY: The blob is not set, so there are no references to it. @@ -33,7 +36,7 @@ pub fn write(data: &[u8], offset: usize) -> Result<(), Error> { let blob = unwrap!(TRANSLATIONS_ON_FLASH.try_write()); let result = { if blob.is_some() { - return Err(value_error!("Translations blob already set")); + return Err(value_error!(c"Translations blob already set")); } // SAFETY: The blob is not set, so there are no references to it. @@ -42,7 +45,7 @@ pub fn write(data: &[u8], offset: usize) -> Result<(), Error> { if result { Ok(()) } else { - Err(value_error!("Failed to write translations blob")) + Err(value_error!(c"Failed to write translations blob")) } } @@ -92,7 +95,7 @@ pub fn init() { /// If the blob is locked by a reader, `deinit()` will return an error. pub fn deinit() -> Result<(), Error> { let Some(mut blob) = TRANSLATIONS_ON_FLASH.try_write() else { - return Err(value_error!("Translations are in use.")); + return Err(value_error!(c"Translations are in use.")); }; *blob = None; Ok(()) @@ -116,5 +119,5 @@ pub fn deinit() -> Result<(), Error> { pub fn get() -> Result>>, Error> { TRANSLATIONS_ON_FLASH .try_read() - .ok_or_else(|| value_error!("Translations are in use.")) + .ok_or(value_error!(c"Translations are in use.")) } diff --git a/core/embed/rust/src/translations/generated/translated_string.rs b/core/embed/rust/src/translations/generated/translated_string.rs index 6f3f09a532..e898761831 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs +++ b/core/embed/rust/src/translations/generated/translated_string.rs @@ -6,7 +6,8 @@ #[cfg(feature = "micropython")] use crate::micropython::qstr::Qstr; -#[derive(Debug, Copy, Clone, FromPrimitive, PartialEq, Eq)] +#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] #[repr(u16)] #[allow(non_camel_case_types)] pub enum TranslatedString { @@ -17,24 +18,24 @@ pub enum TranslatedString { addr_mismatch__wrong_derivation_path = 4, // "Wrong derivation path for selected account." addr_mismatch__xpub_mismatch = 5, // "XPUB mismatch?" address__public_key = 6, // "Public key" - address__title_cosigner = 7, // "COSIGNER" - address__title_receive_address = 8, // "RECEIVE ADDRESS" - address__title_yours = 9, // "YOURS" - address_details__derivation_path = 10, // "Derivation path:" - address_details__title_receive_address = 11, // "RECEIVE ADDRESS" - address_details__title_receiving_to = 12, // "RECEIVING TO" + address__title_cosigner = 7, // "Cosigner" + address__title_receive_address = 8, // "Receive address" + address__title_yours = 9, // "Yours" + address_details__derivation_path_colon = 10, // "Derivation path:" + address_details__title_receive_address = 11, // "Receive address" + address_details__title_receiving_to = 12, // "Receiving to" authenticate__confirm_template = 13, // "Allow connected computer to confirm your {0} is genuine?" authenticate__header = 14, // "Authenticate device" - auto_lock__change_template = 15, // "Auto-lock your Trezor after {0} of inactivity?" - auto_lock__title = 16, // "AUTO-LOCK DELAY" + auto_lock__change_template = 15, // "Auto-lock Trezor after {0} of inactivity?" + auto_lock__title = 16, // "Auto-lock delay" backup__can_back_up_anytime = 17, // "You can back up your Trezor once, at any time." backup__it_should_be_backed_up = 18, // "You should back up your new wallet right now." backup__it_should_be_backed_up_now = 19, // "It should be backed up now!" - backup__new_wallet_created = 20, // "New wallet created.\n" - backup__new_wallet_successfully_created = 21, // "New wallet created successfully." + backup__new_wallet_created = 20, // "Wallet created.\n" + backup__new_wallet_successfully_created = 21, // "Wallet created successfully." backup__recover_anytime = 22, // "You can use your backup to recover your wallet at any time." - backup__title_backup_wallet = 23, // "BACK UP WALLET" - backup__title_skip = 24, // "SKIP BACKUP" + backup__title_backup_wallet = 23, // "Back up wallet" + backup__title_skip = 24, // "Skip backup" backup__want_to_skip = 25, // "Are you sure you want to skip the backup?" #[cfg(feature = "universal_fw")] binance__buy = 26, // "Buy" @@ -72,59 +73,59 @@ pub enum TranslatedString { bitcoin__new_fee_rate = 47, // "New fee rate:" bitcoin__simple_send_of = 48, // "Simple send of" bitcoin__ticket_amount = 49, // "Ticket amount:" - bitcoin__title_confirm_details = 50, // "CONFIRM DETAILS" - bitcoin__title_finalize_transaction = 51, // "FINALIZE TRANSACTION" - bitcoin__title_high_mining_fee = 52, // "HIGH MINING FEE" - bitcoin__title_meld_transaction = 53, // "MELD TRANSACTIONS" - bitcoin__title_modify_amount = 54, // "MODIFY AMOUNT" - bitcoin__title_payjoin = 55, // "PAYJOIN" - bitcoin__title_proof_of_ownership = 56, // "PROOF OF OWNERSHIP" - bitcoin__title_purchase_ticket = 57, // "PURCHASE TICKET" - bitcoin__title_update_transaction = 58, // "UPDATE TRANSACTION" + bitcoin__title_confirm_details = 50, // "Confirm details" + bitcoin__title_finalize_transaction = 51, // "Finalize transaction" + bitcoin__title_high_mining_fee = 52, // "High mining fee" + bitcoin__title_meld_transaction = 53, // "Meld transactions" + bitcoin__title_modify_amount = 54, // "Modify amount" + bitcoin__title_payjoin = 55, // "Payjoin" + bitcoin__title_proof_of_ownership = 56, // "Proof of ownership" + bitcoin__title_purchase_ticket = 57, // "Purchase ticket" + bitcoin__title_update_transaction = 58, // "Update transaction" bitcoin__unknown_path = 59, // "Unknown path" bitcoin__unknown_transaction = 60, // "Unknown transaction" bitcoin__unusually_high_fee = 61, // "Unusually high fee." bitcoin__unverified_external_inputs = 62, // "The transaction contains unverified external inputs." bitcoin__valid_signature = 63, // "The signature is valid." bitcoin__voting_rights = 64, // "Voting rights to:" - buttons__abort = 65, // "ABORT" - buttons__access = 66, // "ACCESS" - buttons__again = 67, // "AGAIN" - buttons__allow = 68, // "ALLOW" - buttons__back = 69, // "BACK" - buttons__back_up = 70, // "BACK UP" - buttons__cancel = 71, // "CANCEL" - buttons__change = 72, // "CHANGE" - buttons__check = 73, // "CHECK" - buttons__check_again = 74, // "CHECK AGAIN" - buttons__close = 75, // "CLOSE" - buttons__confirm = 76, // "CONFIRM" - buttons__continue = 77, // "CONTINUE" - buttons__details = 78, // "DETAILS" - buttons__enable = 79, // "ENABLE" - buttons__enter = 80, // "ENTER" - buttons__enter_share = 81, // "ENTER SHARE" - buttons__export = 82, // "EXPORT" - buttons__format = 83, // "FORMAT" - buttons__go_back = 84, // "GO BACK" - buttons__hold_to_confirm = 85, // "HOLD TO CONFIRM" - buttons__info = 86, // "INFO" - buttons__install = 87, // "INSTALL" - buttons__more_info = 88, // "MORE INFO" - buttons__ok_i_understand = 89, // "OK, I UNDERSTAND" - buttons__purchase = 90, // "PURCHASE" - buttons__quit = 91, // "QUIT" - buttons__restart = 92, // "RESTART" - buttons__retry = 93, // "RETRY" - buttons__select = 94, // "SELECT" - buttons__set = 95, // "SET" - buttons__show_all = 96, // "SHOW ALL" - buttons__show_details = 97, // "SHOW DETAILS" - buttons__show_words = 98, // "SHOW WORDS" - buttons__skip = 99, // "SKIP" - buttons__try_again = 100, // "TRY AGAIN" - buttons__turn_off = 101, // "TURN OFF" - buttons__turn_on = 102, // "TURN ON" + buttons__abort = 65, // "Abort" + buttons__access = 66, // "Access" + buttons__again = 67, // "Again" + buttons__allow = 68, // "Allow" + buttons__back = 69, // "Back" + buttons__back_up = 70, // "Back up" + buttons__cancel = 71, // "Cancel" + buttons__change = 72, // "Change" + buttons__check = 73, // "Check" + buttons__check_again = 74, // "Check again" + buttons__close = 75, // "Close" + buttons__confirm = 76, // "Confirm" + buttons__continue = 77, // "Continue" + buttons__details = 78, // "Details" + buttons__enable = 79, // "Enable" + buttons__enter = 80, // "Enter" + buttons__enter_share = 81, // "Enter share" + buttons__export = 82, // "Export" + buttons__format = 83, // "Format" + buttons__go_back = 84, // "Go back" + buttons__hold_to_confirm = 85, // "Hold to confirm" + buttons__info = 86, // "Info" + buttons__install = 87, // "Install" + buttons__more_info = 88, // "More info" + buttons__ok_i_understand = 89, // "Ok, I understand" + buttons__purchase = 90, // "Purchase" + buttons__quit = 91, // "Quit" + buttons__restart = 92, // "Restart" + buttons__retry = 93, // "Retry" + buttons__select = 94, // "Select" + buttons__set = 95, // "Set" + buttons__show_all = 96, // "Show all" + buttons__show_details = 97, // "Show details" + buttons__show_words = 98, // "Show words" + buttons__skip = 99, // "Skip" + buttons__try_again = 100, // "Try again" + buttons__turn_off = 101, // "Turn off" + buttons__turn_on = 102, // "Turn on" #[cfg(feature = "universal_fw")] cardano__addr_base = 103, // "Base" #[cfg(feature = "universal_fw")] @@ -347,21 +348,21 @@ pub enum TranslatedString { coinjoin__do_not_disconnect = 213, // "Do not disconnect your Trezor!" coinjoin__max_mining_fee = 214, // "Max mining fee" coinjoin__max_rounds = 215, // "Max rounds" - coinjoin__title = 216, // "AUTHORIZE COINJOIN" - coinjoin__title_do_not_disconnect = 217, // "DO NOT DISCONNECT YOUR TREZOR!" - coinjoin__title_progress = 218, // "COINJOIN IN PROGRESS" + coinjoin__title = 216, // "Authorize coinjoin" + coinjoin__title_do_not_disconnect = 217, // "Do not disconnect your trezor!" + coinjoin__title_progress = 218, // "Coinjoin in progress" coinjoin__waiting_for_others = 219, // "Waiting for others" - confirm_total__fee_rate = 220, // "Fee rate:" + confirm_total__fee_rate_colon = 220, // "Fee rate:" confirm_total__sending_from_account = 221, // "Sending from account:" - confirm_total__title_fee = 222, // "FEE INFORMATION" - confirm_total__title_sending_from = 223, // "SENDING FROM" + confirm_total__title_fee = 222, // "Fee info" + confirm_total__title_sending_from = 223, // "Sending from" debug__loading_seed = 224, // "Loading seed" debug__loading_seed_not_recommended = 225, // "Loading private seed is not recommended." device_name__change_template = 226, // "Change device name to {0}?" - device_name__title = 227, // "DEVICE NAME" + device_name__title = 227, // "Device name" entropy__send = 228, // "Do you really want to send entropy?" - entropy__title = 229, // "INTERNAL ENTROPY" - entropy__title_confirm = 230, // "CONFIRM ENTROPY" + entropy__title = 229, // "\"\"" + entropy__title_confirm = 230, // "Confirm entropy" #[cfg(feature = "universal_fw")] eos__about_to_sign_template = 231, // "You are about to sign {0}." #[cfg(feature = "universal_fw")] @@ -420,8 +421,7 @@ pub enum TranslatedString { eos__sell_ram = 258, // "Sell RAM" #[cfg(feature = "universal_fw")] eos__sender = 259, // "Sender:" - #[cfg(feature = "universal_fw")] - eos__sign_transaction = 260, // "Sign transaction" + send__sign_transaction = 260, // "Sign transaction" #[cfg(feature = "universal_fw")] eos__threshold = 261, // "Threshold:" #[cfg(feature = "universal_fw")] @@ -449,11 +449,11 @@ pub enum TranslatedString { #[cfg(feature = "universal_fw")] ethereum__data_size_template = 273, // "Size: {0} bytes" #[cfg(feature = "universal_fw")] - ethereum__gas_limit = 274, // "Gas limit:" + ethereum__gas_limit = 274, // "Gas limit" #[cfg(feature = "universal_fw")] - ethereum__gas_price = 275, // "Gas price:" + ethereum__gas_price = 275, // "Gas price" #[cfg(feature = "universal_fw")] - ethereum__max_gas_price = 276, // "Max gas price:" + ethereum__max_gas_price = 276, // "Max gas price" #[cfg(feature = "universal_fw")] ethereum__name_and_version = 277, // "Name and version" #[cfg(feature = "universal_fw")] @@ -461,7 +461,7 @@ pub enum TranslatedString { #[cfg(feature = "universal_fw")] ethereum__no_message_field = 279, // "No message field" #[cfg(feature = "universal_fw")] - ethereum__priority_fee = 280, // "Priority fee:" + ethereum__priority_fee = 280, // "Priority fee" #[cfg(feature = "universal_fw")] ethereum__show_full_array = 281, // "Show full array" #[cfg(feature = "universal_fw")] @@ -473,17 +473,17 @@ pub enum TranslatedString { #[cfg(feature = "universal_fw")] ethereum__sign_eip712 = 285, // "Really sign EIP-712 typed data?" #[cfg(feature = "universal_fw")] - ethereum__title_confirm_data = 286, // "CONFIRM DATA" + ethereum__title_confirm_data = 286, // "Confirm data" #[cfg(feature = "universal_fw")] - ethereum__title_confirm_domain = 287, // "CONFIRM DOMAIN" + ethereum__title_confirm_domain = 287, // "Confirm domain" #[cfg(feature = "universal_fw")] - ethereum__title_confirm_message = 288, // "CONFIRM MESSAGE" + ethereum__title_confirm_message = 288, // "Confirm message" #[cfg(feature = "universal_fw")] - ethereum__title_confirm_struct = 289, // "CONFIRM STRUCT" + ethereum__title_confirm_struct = 289, // "Confirm struct" #[cfg(feature = "universal_fw")] - ethereum__title_confirm_typed_data = 290, // "CONFIRM TYPED DATA" + ethereum__title_confirm_typed_data = 290, // "Confirm typed data" #[cfg(feature = "universal_fw")] - ethereum__title_signing_address = 291, // "SIGNING ADDRESS" + ethereum__title_signing_address = 291, // "Signing address" #[cfg(feature = "universal_fw")] ethereum__units_template = 292, // "{0} units" #[cfg(feature = "universal_fw")] @@ -492,7 +492,7 @@ pub enum TranslatedString { ethereum__valid_signature = 294, // "The signature is valid." experimental_mode__enable = 295, // "Enable experimental features?" experimental_mode__only_for_dev = 296, // "Only for development and beta testing!" - experimental_mode__title = 297, // "EXPERIMENTAL MODE" + experimental_mode__title = 297, // "Experimental mode" #[cfg(feature = "universal_fw")] fido__already_registered = 298, // "Already registered" #[cfg(feature = "universal_fw")] @@ -514,39 +514,39 @@ pub enum TranslatedString { #[cfg(feature = "universal_fw")] fido__please_enable_pin_protection = 307, // "Please enable PIN protection." #[cfg(feature = "universal_fw")] - fido__title_authenticate = 308, // "FIDO2 AUTHENTICATE" + fido__title_authenticate = 308, // "FIDO2 authenticate" #[cfg(feature = "universal_fw")] - fido__title_import_credential = 309, // "IMPORT CREDENTIAL" + fido__title_import_credential = 309, // "Import credential" #[cfg(feature = "universal_fw")] - fido__title_list_credentials = 310, // "LIST CREDENTIALS" + fido__title_list_credentials = 310, // "List credentials" #[cfg(feature = "universal_fw")] - fido__title_register = 311, // "FIDO2 REGISTER" + fido__title_register = 311, // "FIDO2 register" #[cfg(feature = "universal_fw")] - fido__title_remove_credential = 312, // "REMOVE CREDENTIAL" + fido__title_remove_credential = 312, // "Remove credential" #[cfg(feature = "universal_fw")] - fido__title_reset = 313, // "FIDO2 RESET" + fido__title_reset = 313, // "FIDO2 reset" #[cfg(feature = "universal_fw")] - fido__title_u2f_auth = 314, // "U2F AUTHENTICATE" + fido__title_u2f_auth = 314, // "U2F authenticate" #[cfg(feature = "universal_fw")] - fido__title_u2f_register = 315, // "U2F REGISTER" + fido__title_u2f_register = 315, // "U2F register" #[cfg(feature = "universal_fw")] - fido__title_verify_user = 316, // "FIDO2 VERIFY USER" + fido__title_verify_user = 316, // "FIDO2 verify user" #[cfg(feature = "universal_fw")] fido__unable_to_verify_user = 317, // "Unable to verify user." #[cfg(feature = "universal_fw")] fido__wanna_erase_credentials = 318, // "Do you really want to erase all credentials?" - firmware_update__title = 319, // "UPDATE FIRMWARE" - firmware_update__title_fingerprint = 320, // "FW FINGERPRINT" + firmware_update__title = 319, // "Update firmware" + firmware_update__title_fingerprint = 320, // "FW fingerprint" homescreen__click_to_connect = 321, // "Click to Connect" homescreen__click_to_unlock = 322, // "Click to Unlock" - homescreen__title_backup_failed = 323, // "BACKUP FAILED" - homescreen__title_backup_needed = 324, // "BACKUP NEEDED" - homescreen__title_coinjoin_authorized = 325, // "COINJOIN AUTHORIZED" - homescreen__title_experimental_mode = 326, // "EXPERIMENTAL MODE" - homescreen__title_no_usb_connection = 327, // "NO USB CONNECTION" - homescreen__title_pin_not_set = 328, // "PIN NOT SET" - homescreen__title_seedless = 329, // "SEEDLESS" - homescreen__title_set = 330, // "CHANGE HOMESCREEN?" + homescreen__title_backup_failed = 323, // "Backup failed" + homescreen__title_backup_needed = 324, // "Backup needed" + homescreen__title_coinjoin_authorized = 325, // "Coinjoin authorized" + homescreen__title_experimental_mode = 326, // "Experimental mode" + homescreen__title_no_usb_connection = 327, // "No USB connection" + homescreen__title_pin_not_set = 328, // "PIN not set" + homescreen__title_seedless = 329, // "Seedless" + homescreen__title_set = 330, // "Change wallpaper" inputs__back = 331, // "BACK" inputs__cancel = 332, // "CANCEL" inputs__delete = 333, // "DELETE" @@ -554,30 +554,30 @@ pub enum TranslatedString { inputs__return = 335, // "RETURN" inputs__show = 336, // "SHOW" inputs__space = 337, // "SPACE" - joint__title = 338, // "JOINT TRANSACTION" + joint__title = 338, // "Joint transaction" joint__to_the_total_amount = 339, // "To the total amount:" joint__you_are_contributing = 340, // "You are contributing:" language__change_to_template = 341, // "Change language to {0}?" language__changed = 342, // "Language changed successfully" language__progress = 343, // "Changing language" - language__title = 344, // "LANGUAGE SETTINGS" + language__title = 344, // "Language settings" lockscreen__tap_to_connect = 345, // "Tap to connect" lockscreen__tap_to_unlock = 346, // "Tap to unlock" - lockscreen__title_locked = 347, // "LOCKED" - lockscreen__title_not_connected = 348, // "NOT CONNECTED" + lockscreen__title_locked = 347, // "Locked" + lockscreen__title_not_connected = 348, // "Not connected" misc__decrypt_value = 349, // "Decrypt value" misc__encrypt_value = 350, // "Encrypt value" - misc__title_suite_labeling = 351, // "SUITE LABELING" + misc__title_suite_labeling = 351, // "Suite labeling" modify_amount__decrease_amount = 352, // "Decrease amount by:" modify_amount__increase_amount = 353, // "Increase amount by:" modify_amount__new_amount = 354, // "New amount:" - modify_amount__title = 355, // "MODIFY AMOUNT" + modify_amount__title = 355, // "Modify amount" modify_fee__decrease_fee = 356, // "Decrease fee by:" modify_fee__fee_rate = 357, // "Fee rate:" modify_fee__increase_fee = 358, // "Increase fee by:" modify_fee__new_transaction_fee = 359, // "New transaction fee:" modify_fee__no_change = 360, // "Fee did not change.\n" - modify_fee__title = 361, // "MODIFY FEE" + modify_fee__title = 361, // "Modify fee" modify_fee__transaction_fee = 362, // "Transaction fee:" #[cfg(feature = "universal_fw")] monero__confirm_export = 363, // "Confirm export" @@ -717,19 +717,19 @@ pub enum TranslatedString { nem__unencrypted = 430, // "Unencrypted:" #[cfg(feature = "universal_fw")] nem__unknown_mosaic = 431, // "Unknown mosaic!" - passphrase__access_hidden_wallet = 432, // "Access hidden wallet?" - passphrase__always_on_device = 433, // "Do you really want to enter passphrase always on the device?" + passphrase__access_wallet = 432, // "Access passphrase wallet?" + passphrase__always_on_device = 433, // "Always enter your passphrase on Trezor?" passphrase__from_host_not_shown = 434, // "Passphrase provided by host will be used but will not be displayed due to the device settings." - passphrase__hidden_wallet = 435, // "Hidden wallet" + passphrase__wallet = 435, // "Passphrase wallet" passphrase__hide = 436, // "Hide passphrase coming from host?" - passphrase__next_screen_will_show_passphrase = 437, // "Next screen will show the passphrase." + passphrase__next_screen_will_show_passphrase = 437, // "The next screen shows your passphrase." passphrase__please_enter = 438, // "Please enter your passphrase." passphrase__revoke_on_device = 439, // "Do you want to revoke the passphrase on device setting?" - passphrase__title_confirm = 440, // "CONFIRM PASSPHRASE" - passphrase__title_enter = 441, // "ENTER PASSPHRASE" - passphrase__title_hide = 442, // "HIDE PASSPHRASE" - passphrase__title_settings = 443, // "PASSPHRASE SETTINGS" - passphrase__title_source = 444, // "PASSPHRASE SOURCE" + passphrase__title_confirm = 440, // "Confirm passphrase" + passphrase__title_enter = 441, // "Enter passphrase" + passphrase__title_hide = 442, // "Hide passphrase" + passphrase__title_settings = 443, // "Passphrase settings" + passphrase__title_source = 444, // "Passphrase source" passphrase__turn_off = 445, // "Turn off passphrase protection?" passphrase__turn_on = 446, // "Turn on passphrase protection?" pin__change = 447, // "Change PIN?" @@ -750,9 +750,9 @@ pub enum TranslatedString { pin__reenter_new = 462, // "Re-enter new PIN" pin__reenter_to_confirm = 463, // "Please re-enter PIN to confirm." pin__should_be_long = 464, // "PIN should be 4-50 digits long." - pin__title_check_pin = 465, // "CHECK PIN" - pin__title_settings = 466, // "PIN SETTINGS" - pin__title_wrong_pin = 467, // "WRONG PIN" + pin__title_check_pin = 465, // "Check PIN" + pin__title_settings = 466, // "PIN settings" + pin__title_wrong_pin = 467, // "Wrong PIN" pin__tries_left = 468, // "tries left" pin__turn_off = 469, // "Are you sure you want to turn off PIN protection?" pin__turn_on = 470, // "Turn on PIN protection?" @@ -771,25 +771,25 @@ pub enum TranslatedString { progress__loading_transaction = 483, // "Loading transaction..." progress__locking_device = 484, // "Locking the device..." progress__one_second_left = 485, // "1 second left" - progress__please_wait = 486, // "PLEASE WAIT" - storage_msg__processing = 487, // "PROCESSING" + progress__please_wait = 486, // "Please wait" + storage_msg__processing = 487, // "Processing" progress__refreshing = 488, // "Refreshing..." progress__signing_transaction = 489, // "Signing transaction..." progress__syncing = 490, // "Syncing..." progress__x_seconds_left_template = 491, // "{0} seconds left" reboot_to_bootloader__restart = 492, // "Trezor will restart in bootloader mode." - reboot_to_bootloader__title = 493, // "GO TO BOOTLOADER" + reboot_to_bootloader__title = 493, // "Go to bootloader" reboot_to_bootloader__version_by_template = 494, // "Firmware version {0}\nby {1}" recovery__cancel_dry_run = 495, // "Cancel backup check" recovery__check_dry_run = 496, // "Check your backup?" recovery__cursor_will_change = 497, // "Position of the cursor will change between entries for enhanced security." - recovery__dry_run_bip39_valid_match = 498, // "The entered recovery wallet backup is valid and matches the one in the device." + recovery__dry_run_bip39_valid_match = 498, // "The entered wallet backup is valid and matches the one in this device." recovery__dry_run_bip39_valid_mismatch = 499, // "The entered wallet backup is valid but does not match the one in the device." recovery__dry_run_slip39_valid_match = 500, // "The entered recovery shares are valid and match what is currently in the device." recovery__dry_run_slip39_valid_mismatch = 501, // "The entered recovery shares are valid but do not match what is currently in the device." recovery__enter_any_share = 502, // "Enter any share" recovery__enter_backup = 503, // "Enter your backup." - recovery__enter_different_share = 504, // "Please enter a different share." + recovery__enter_different_share = 504, // "Enter a different share." recovery__enter_share_from_diff_group = 505, // "Enter share from a different group." recovery__group_num_template = 506, // "Group {0}" recovery__group_threshold_reached = 507, // "Group threshold reached." @@ -799,36 +799,36 @@ pub enum TranslatedString { recovery__num_of_words = 511, // "Select the number of words in your backup." recovery__only_first_n_letters = 512, // "You'll only have to select the first 2-4 letters of each word." recovery__progress_will_be_lost = 513, // "All progress will be lost." - recovery__select_num_of_words = 514, // "Select the number of words in your backup." + recovery__select_num_of_words = 514, // "\"\"" recovery__share_already_entered = 515, // "Share already entered" - recovery__share_from_another_shamir = 516, // "You have entered a share from another Shamir Backup." + recovery__share_from_another_multi_share_backup = 516, // "You have entered a share from a different backup." recovery__share_num_template = 517, // "Share {0}" - recovery__title = 518, // "RECOVER WALLET" - recovery__title_cancel_dry_run = 519, // "CANCEL BACKUP CHECK" - recovery__title_cancel_recovery = 520, // "CANCEL RECOVERY" - recovery__title_dry_run = 521, // "BACKUP CHECK" - recovery__title_recover = 522, // "RECOVER WALLET" - recovery__title_remaining_shares = 523, // "REMAINING SHARES" + recovery__title = 518, // "Recover wallet" + recovery__title_cancel_dry_run = 519, // "Cancel backup check" + recovery__title_cancel_recovery = 520, // "Cancel recovery" + recovery__title_dry_run = 521, // "Backup check" + recovery__title_recover = 522, // "Recover wallet" + recovery__title_remaining_shares = 523, // "Remaining shares" recovery__type_word_x_of_y_template = 524, // "Type word {0} of {1}" - recovery__wallet_recovered = 525, // "Wallet recovered successfully" + recovery__wallet_recovered = 525, // "Wallet recovery completed" recovery__wanna_cancel_dry_run = 526, // "Are you sure you want to cancel the backup check?" recovery__wanna_cancel_recovery = 527, // "Are you sure you want to cancel the recovery process?" recovery__word_count_template = 528, // "({0} words)" - recovery__word_x_of_y_template = 529, // "WORD {0} OF {1}" + recovery__word_x_of_y_template = 529, // "Word {0} of {1}" recovery__x_more_items_starting_template_plural = 530, // "{count} more {plural} starting" - recovery__x_more_shares_needed_template_plural = 531, // "{count} more {plural} needed." - recovery__x_of_y_entered_template = 532, // "{0} of {1} shares entered successfully." + recovery__x_more_shares_needed_template_plural = 531, // "{count} more {plural} needed" + recovery__x_of_y_entered_template = 532, // "{0} of {1} shares entered" recovery__you_have_entered = 533, // "You have entered" reset__advanced_group_threshold_info = 534, // "The group threshold specifies the number of groups required to recover your wallet." reset__all_x_of_y_template = 535, // "all {0} of {1} shares" reset__any_x_of_y_template = 536, // "any {0} of {1} shares" - reset__button_create = 537, // "CREATE WALLET" - reset__button_recover = 538, // "RECOVER WALLET" + reset__button_create = 537, // "Create wallet" + reset__button_recover = 538, // "Recover wallet" reset__by_continuing = 539, // "By continuing you agree to Trezor Company's terms and conditions." - reset__check_backup_title = 540, // "CHECK BACKUP" - reset__check_group_share_title_template = 541, // "CHECK G{0} - SHARE {1}" - reset__check_wallet_backup_title = 542, // "CHECK WALLET BACKUP" - reset__check_share_title_template = 543, // "CHECK SHARE #{0}" + reset__check_backup_title = 540, // "Check backup" + reset__check_group_share_title_template = 541, // "Check g{0} - share {1}" + reset__check_wallet_backup_title = 542, // "Check wallet backup" + reset__check_share_title_template = 543, // "Check share #{0}" reset__continue_with_next_share = 544, // "Continue with the next share." reset__continue_with_share_template = 545, // "Continue with share #{0}." reset__finished_verifying_group_template = 546, // "You have finished verifying your recovery shares for group {0}." @@ -837,7 +837,7 @@ pub enum TranslatedString { reset__group_description = 549, // "A group is made up of recovery shares." reset__group_info = 550, // "Each group has a set number of shares and its own threshold. In the next steps you will set the numbers of shares and the thresholds." reset__group_share_checked_successfully_template = 551, // "Group {0} - Share {1} checked successfully." - reset__group_share_title_template = 552, // "GROUP {0} - SHARE {1}" + reset__group_share_title_template = 552, // "Group {0} - share {1}" reset__more_info_at = 553, // "More info at" reset__need_all_share_template = 554, // "For recovery you need all {0} of the shares." reset__need_any_share_template = 555, // "For recovery you need any {0} of the shares." @@ -845,21 +845,21 @@ pub enum TranslatedString { reset__needed_to_recover_your_wallet = 557, // "needed to recover your wallet. " reset__never_make_digital_copy = 558, // "Never put your backup anywhere digital." reset__num_of_share_holders_template = 559, // "{0} people or locations will each hold one share." - reset__num_of_shares_advanced_info_template = 560, // "Each recovery share is a sequence of 20 words. Next you will choose the threshold number of shares needed to form Group {0}." - reset__num_of_shares_basic_info = 561, // "Each recovery share is a sequence of 20 words. Next you will choose how many shares you need to recover your wallet." + reset__num_of_shares_advanced_info_template = 560, // "Each recovery share is a sequence of {0} words. Next you will choose the threshold number of shares needed to form Group {1}." + reset__num_of_shares_basic_info_template = 561, // "Each recovery share is a sequence of {0} words. Next you will choose how many shares you need to recover your wallet." reset__num_shares_for_group_template = 562, // "The required number of shares to form Group {0}." reset__number_of_shares_info = 563, // "= total number of unique word lists used for wallet backup." reset__one_share = 564, // "1 share" reset__only_one_share_will_be_created = 565, // "Only one share will be created." - reset__recovery_wallet_backup_title = 566, // "WALLET BACKUP" - reset__recovery_share_title_template = 567, // "RECOVERY SHARE #{0}" + reset__recovery_wallet_backup_title = 566, // "Wallet backup" + reset__recovery_share_title_template = 567, // "Recovery share #{0}" reset__required_number_of_groups = 568, // "The required number of groups for recovery." reset__select_correct_word = 569, // "Select the correct word for each position." - reset__select_word_template = 570, // "SELECT {0} WORD" + reset__select_word_template = 570, // "Select {0} word" reset__select_word_x_of_y_template = 571, // "Select word {0} of {1}:" reset__set_it_to_count_template = 572, // "Set it to {0} and you will need " - reset__share_checked_successfully_template = 573, // "Recovery share #{0} checked successfully." - reset__share_words_title = 574, // "STANDARD BACKUP" + reset__share_checked_successfully_template = 573, // "Share #{0} checked successfully." + reset__share_words_title = 574, // "Standard backup" reset__slip39_checklist_num_groups = 575, // "Number of groups" reset__slip39_checklist_num_shares = 576, // "Number of shares" reset__slip39_checklist_set_num_groups = 577, // "Set number of groups" @@ -867,26 +867,26 @@ pub enum TranslatedString { reset__slip39_checklist_set_sizes = 579, // "Set sizes and thresholds" reset__slip39_checklist_set_sizes_longer = 580, // "Set size and threshold for each group" reset__slip39_checklist_set_threshold = 581, // "Set threshold" - reset__slip39_checklist_title = 582, // "BACKUP CHECKLIST" + reset__slip39_checklist_title = 582, // "Backup checklist" reset__slip39_checklist_write_down = 583, // "Write down and check all shares" - reset__slip39_checklist_write_down_recovery = 584, // "Write down and check all recovery shares" + reset__slip39_checklist_write_down_recovery = 584, // "Write down & check all wallet backup shares" reset__the_threshold_sets_the_number_of_shares = 585, // "The threshold sets the number of shares " reset__threshold_info = 586, // "= minimum number of unique word lists used for recovery." - reset__title_backup_is_done = 587, // "BACKUP IS DONE" - reset__title_create_wallet = 588, // "CREATE WALLET" - reset__title_create_wallet_shamir = 589, // "CREATE WALLET (SHAMIR)" - reset__title_group_threshold = 590, // "GROUP THRESHOLD" - reset__title_number_of_groups = 591, // "NUMBER OF GROUPS" - reset__title_number_of_shares = 592, // "NUMBER OF SHARES" - reset__title_set_group_threshold = 593, // "SET GROUP THRESHOLD" - reset__title_set_number_of_groups = 594, // "SET NUMBER OF GROUPS" - reset__title_set_number_of_shares = 595, // "SET NUMBER OF SHARES" - reset__title_set_threshold = 596, // "SET THRESHOLD" + reset__title_backup_is_done = 587, // "Backup is done" + reset__title_create_wallet = 588, // "Create wallet" + reset__title_create_wallet_shamir = 589, // "\"\"" + reset__title_group_threshold = 590, // "Group threshold" + reset__title_number_of_groups = 591, // "Number of groups" + reset__title_number_of_shares = 592, // "Number of shares" + reset__title_set_group_threshold = 593, // "Set group threshold" + reset__title_set_number_of_groups = 594, // "Set number of groups" + reset__title_set_number_of_shares = 595, // "Set number of shares" + reset__title_set_threshold = 596, // "Set threshold" reset__to_form_group_template = 597, // "to form Group {0}." reset__tos_link = 598, // "trezor.io/tos" reset__total_number_of_shares_in_group_template = 599, // "Set the total number of shares in Group {0}." reset__use_your_backup = 600, // "Use your backup when you need to recover your wallet." - reset__write_down_words_template = 601, // "Write down all {0} words in order." + reset__write_down_words_template = 601, // "Write the following {0} words in order on your wallet backup card." reset__wrong_word_selected = 602, // "Wrong word selected!" reset__you_need_one_share = 603, // "For recovery you need 1 share." reset__your_backup_is_done = 604, // "Your backup is done." @@ -898,13 +898,13 @@ pub enum TranslatedString { rotation__east = 608, // "east" rotation__north = 609, // "north" rotation__south = 610, // "south" - rotation__title_change = 611, // "CHANGE ROTATION" + rotation__title_change = 611, // "Change rotation" rotation__west = 612, // "west" safety_checks__approve_unsafe_always = 613, // "Trezor will allow you to approve some actions which might be unsafe." safety_checks__approve_unsafe_temporary = 614, // "Trezor will temporarily allow you to approve some actions which might be unsafe." safety_checks__enforce_strict = 615, // "Do you really want to enforce strict safety checks (recommended)?" - safety_checks__title = 616, // "SAFETY CHECKS" - safety_checks__title_safety_override = 617, // "SAFETY OVERRIDE" + safety_checks__title = 616, // "Safety checks" + safety_checks__title_safety_override = 617, // "Safety override" sd_card__all_data_will_be_lost = 618, // "All data on the SD card will be lost." sd_card__card_required = 619, // "SD card required." sd_card__disable = 620, // "Do you really want to remove SD card protection from your device?" @@ -920,36 +920,36 @@ pub enum TranslatedString { sd_card__refresh = 630, // "Do you really want to replace the current SD card secret with a newly generated one?" sd_card__refreshed = 631, // "You have successfully refreshed SD protection." sd_card__restart = 632, // "Do you want to restart Trezor in bootloader mode?" - sd_card__title = 633, // "SD CARD PROTECTION" - sd_card__title_problem = 634, // "SD CARD PROBLEM" + sd_card__title = 633, // "SD card protection" + sd_card__title_problem = 634, // "SD card problem" sd_card__unknown_filesystem = 635, // "Unknown filesystem." sd_card__unplug_and_insert_correct = 636, // "Please unplug the device and insert the correct SD card." sd_card__use_different_card = 637, // "Use a different card or format the SD card to the FAT32 filesystem." sd_card__wanna_format = 638, // "Do you really want to format the SD card?" sd_card__wrong_sd_card = 639, // "Wrong SD card." send__address_path = 640, // "address path" - send__confirm_sending = 641, // "SENDING AMOUNT" + send__confirm_sending = 641, // "Sending amount" send__from_multiple_accounts = 642, // "Sending from multiple accounts." send__including_fee = 643, // "Including fee:" - send__maximum_fee = 644, // "Maximum fee:" + send__maximum_fee = 644, // "Maximum fee" send__receiving_to_multisig = 645, // "Receiving to a multisig address." - send__title_confirm_sending = 646, // "CONFIRM SENDING" - send__title_joint_transaction = 647, // "JOINT TRANSACTION" - send__title_receiving_to = 648, // "RECEIVING TO" - send__title_sending = 649, // "SENDING" - send__title_sending_amount = 650, // "SENDING AMOUNT" - send__title_sending_to = 651, // "SENDING TO" + send__title_confirm_sending = 646, // "Confirm sending" + send__title_joint_transaction = 647, // "Joint transaction" + send__title_receiving_to = 648, // "Receiving to" + send__title_sending = 649, // "Sending" + send__title_sending_amount = 650, // "Sending amount" + send__title_sending_to = 651, // "Sending to" send__to_the_total_amount = 652, // "To the total amount:" - send__total_amount = 653, // "Total amount:" + send__total_amount_colon = 653, // "Total amount:" send__transaction_id = 654, // "Transaction ID:" send__you_are_contributing = 655, // "You are contributing:" share_words__words_in_order = 656, // " words in order." share_words__wrote_down_all = 657, // "I wrote down all " sign_message__bytes_template = 658, // "{0} Bytes" - sign_message__confirm_address = 659, // "SIGNING ADDRESS" - sign_message__confirm_message = 660, // "CONFIRM MESSAGE" + sign_message__confirm_address = 659, // "Signing address" + sign_message__confirm_message = 660, // "Confirm message" sign_message__message_size = 661, // "Message size:" - sign_message__verify_address = 662, // "VERIFY ADDRESS" + sign_message__verify_address = 662, // "Verify address" #[cfg(feature = "universal_fw")] solana__account_index = 663, // "Account index" #[cfg(feature = "universal_fw")] @@ -1141,10 +1141,10 @@ pub enum TranslatedString { tutorial__ready_to_use = 758, // "You're ready to\nuse Trezor." tutorial__scroll_down = 759, // "Press right to scroll down to read all content when text doesn't fit on one screen.\n\rPress left to scroll up." tutorial__sure_you_want_skip = 760, // "Are you sure you\nwant to skip the tutorial?" - tutorial__title_hello = 761, // "HELLO" - tutorial__title_screen_scroll = 762, // "SCREEN SCROLL" - tutorial__title_skip = 763, // "SKIP TUTORIAL" - tutorial__title_tutorial_complete = 764, // "TUTORIAL COMPLETE" + tutorial__title_hello = 761, // "Hello" + tutorial__title_screen_scroll = 762, // "Screen scroll" + tutorial__title_skip = 763, // "Skip tutorial" + tutorial__title_tutorial_complete = 764, // "Tutorial complete" tutorial__use_trezor = 765, // "Use Trezor by\nclicking the left and right buttons.\n\rContinue right." tutorial__welcome_press_right = 766, // "Welcome to Trezor. Press right to continue." #[cfg(feature = "universal_fw")] @@ -1152,11 +1152,11 @@ pub enum TranslatedString { #[cfg(feature = "universal_fw")] u2f__set_template = 768, // "Set the U2F counter to {0}?" #[cfg(feature = "universal_fw")] - u2f__title_get = 769, // "GET U2F COUNTER" + u2f__title_get = 769, // "Get U2F counter" #[cfg(feature = "universal_fw")] - u2f__title_set = 770, // "SET U2F COUNTER" + u2f__title_set = 770, // "Set U2F counter" wipe__info = 771, // "All data will be erased." - wipe__title = 772, // "WIPE DEVICE" + wipe__title = 772, // "Wipe device" wipe__want_to_wipe = 773, // "Do you really want to wipe the device?\n" wipe_code__change = 774, // "Change wipe code?" wipe_code__changed = 775, // "Wipe code changed." @@ -1169,13 +1169,13 @@ pub enum TranslatedString { wipe_code__mismatch = 782, // "The wipe codes you entered do not match." wipe_code__reenter = 783, // "Re-enter wipe code" wipe_code__reenter_to_confirm = 784, // "Please re-enter wipe code to confirm." - wipe_code__title_check = 785, // "CHECK WIPE CODE" - wipe_code__title_invalid = 786, // "INVALID WIPE CODE" - wipe_code__title_settings = 787, // "WIPE CODE SETTINGS" + wipe_code__title_check = 785, // "Check wipe code" + wipe_code__title_invalid = 786, // "Invalid wipe code" + wipe_code__title_settings = 787, // "Wipe code settings" wipe_code__turn_off = 788, // "Turn off wipe code protection?" wipe_code__turn_on = 789, // "Turn on wipe code protection?" wipe_code__wipe_code_mismatch = 790, // "Wipe code mismatch" - word_count__title = 791, // "NUMBER OF WORDS" + word_count__title = 791, // "Number of words" words__account = 792, // "Account" words__account_colon = 793, // "Account:" words__address = 794, // "Address" @@ -1203,15 +1203,15 @@ pub enum TranslatedString { words__recipient = 816, // "Recipient" words__sign = 817, // "Sign" words__signer = 818, // "Signer" - words__title_check = 819, // "CHECK" - words__title_group = 820, // "GROUP" - words__title_information = 821, // "INFORMATION" - words__title_remember = 822, // "REMEMBER" - words__title_share = 823, // "SHARE" - words__title_shares = 824, // "SHARES" - words__title_success = 825, // "SUCCESS" - words__title_summary = 826, // "SUMMARY" - words__title_threshold = 827, // "THRESHOLD" + words__title_check = 819, // "Check" + words__title_group = 820, // "Group" + words__title_information = 821, // "Information" + words__title_remember = 822, // "Remember" + words__title_share = 823, // "Share" + words__title_shares = 824, // "Shares" + words__title_success = 825, // "Success" + words__title_summary = 826, // "Summary" + words__title_threshold = 827, // "Threshold" words__unknown = 828, // "Unknown" words__warning = 829, // "Warning" words__writable = 830, // "Writable" @@ -1219,26 +1219,156 @@ pub enum TranslatedString { reboot_to_bootloader__just_a_moment = 832, // "Just a moment..." inputs__previous = 833, // "PREVIOUS" #[cfg(feature = "universal_fw")] - ethereum__staking_claim = 834, // "CLAIM" + ethereum__staking_claim = 834, // "Claim" #[cfg(feature = "universal_fw")] - ethereum__staking_claim_address = 835, // "CLAIM ADDRESS" + ethereum__staking_claim_address = 835, // "Claim address" #[cfg(feature = "universal_fw")] ethereum__staking_claim_intro = 836, // "Claim ETH from Everstake?" #[cfg(feature = "universal_fw")] - ethereum__staking_stake = 837, // "STAKE" + ethereum__staking_stake = 837, // "Stake" #[cfg(feature = "universal_fw")] - ethereum__staking_stake_address = 838, // "STAKE ADDRESS" + ethereum__staking_stake_address = 838, // "Stake address" #[cfg(feature = "universal_fw")] ethereum__staking_stake_intro = 839, // "Stake ETH on Everstake?" #[cfg(feature = "universal_fw")] - ethereum__staking_unstake = 840, // "UNSTAKE" + ethereum__staking_unstake = 840, // "Unstake" #[cfg(feature = "universal_fw")] ethereum__staking_unstake_intro = 841, // "Unstake ETH from Everstake?" - storage_msg__starting = 842, // "STARTING UP" - storage_msg__verifying_pin = 843, // "VERIFYING PIN" - storage_msg__wrong_pin = 844, // "WRONG PIN" - reset__create_x_of_y_shamir_backup_template = 845, // "Do you want to create a {0} of {1} Shamir backup?" - reset__title_shamir_backup = 846, // "SHAMIR BACKUP" + storage_msg__starting = 842, // "Starting up" + storage_msg__verifying_pin = 843, // "Verifying PIN" + storage_msg__wrong_pin = 844, // "Wrong PIN" + reset__create_x_of_y_multi_share_backup_template = 845, // "Do you want to create a {0} of {1} multi-share backup?" + reset__title_shamir_backup = 846, // "Multi-share backup" + #[cfg(feature = "universal_fw")] + cardano__always_abstain = 847, // "Always Abstain" + #[cfg(feature = "universal_fw")] + cardano__always_no_confidence = 848, // "Always No Confidence" + #[cfg(feature = "universal_fw")] + cardano__delegating_to_key_hash = 849, // "Delegating to key hash:" + #[cfg(feature = "universal_fw")] + cardano__delegating_to_script = 850, // "Delegating to script:" + #[cfg(feature = "universal_fw")] + cardano__deposit = 851, // "Deposit:" + #[cfg(feature = "universal_fw")] + cardano__vote_delegation = 852, // "Vote delegation" + instructions__swipe_up = 853, // "Swipe up" + instructions__tap_to_confirm = 854, // "Tap to confirm" + instructions__hold_to_confirm = 855, // "Hold to confirm" + words__important = 856, // "Important" + reset__words_written_down_template = 857, // "I wrote down all {0} words in order." + backup__create_backup_to_prevent_loss = 858, // "Create a backup to avoid losing access to your funds" + reset__check_backup_instructions = 859, // "Let's do a quick check of your backup." + words__instructions = 860, // "Instructions" + words__not_recommended = 861, // "Not recommended!" + address_details__account_info = 862, // "Account info" + address__cancel_contact_support = 863, // "If receive address doesn't match, contact Trezor Support at trezor.io/support." + address__cancel_receive = 864, // "Cancel receive" + address__qr_code = 865, // "QR code" + address_details__derivation_path = 866, // "Derivation path" + instructions__continue_in_app = 867, // "Continue in the app" + words__cancel_and_exit = 868, // "Cancel and exit" + address__confirmed = 869, // "Receive address confirmed" + pin__cancel_description = 870, // "Continue without PIN" + pin__cancel_info = 871, // "Without a PIN, anyone can access this device." + pin__cancel_setup = 872, // "Cancel PIN setup" + send__cancel_sign = 873, // "Cancel sign" + send__send_from = 874, // "Send from" + instructions__hold_to_sign = 875, // "Hold to sign" + confirm_total__fee_rate = 876, // "Fee rate" + send__incl_transaction_fee = 877, // "incl. Transaction fee" + send__total_amount = 878, // "Total amount" + auto_lock__turned_on = 879, // "Auto-lock turned on" + backup__info_multi_share_backup = 880, // "Your wallet backup contains multiple lists of words in a specific order (shares)." + backup__info_single_share_backup = 881, // "Your wallet backup contains {0} words in a specific order." + backup__title_backup_completed = 882, // "Wallet backup completed" + backup__title_create_wallet_backup = 883, // "Create wallet backup" + haptic_feedback__disable = 884, // "Disable haptic feedback?" + haptic_feedback__enable = 885, // "Enable haptic feedback?" + haptic_feedback__subtitle = 886, // "Setting" + haptic_feedback__title = 887, // "Haptic feedback" + instructions__continue_holding = 888, // "Continue\nholding" + instructions__enter_next_share = 889, // "Enter next share" + instructions__hold_to_continue = 890, // "Hold to continue" + instructions__hold_to_exit_tutorial = 891, // "Hold to exit tutorial" + instructions__hold_to_finish_tutorial = 892, // "\"\"" + instructions__learn_more = 893, // "Learn more" + instructions__shares_continue_with_x_template = 894, // "Continue with Share #{0}" + instructions__shares_start_with_1 = 895, // "Start with share #1" + instructions__tap_to_start = 896, // "Tap to start" + passphrase__title_passphrase = 897, // "Passphrase" + recovery__dry_run_backup_not_on_this_device = 898, // "Wallet backup not on this device" + recovery__dry_run_invalid_backup_entered = 899, // "Invalid wallet backup entered" + recovery__dry_run_slip39_valid_all_shares = 900, // "All shares are valid and belong to the backup in this device" + recovery__dry_run_slip39_valid_share = 901, // "Entered share is valid and belongs to the backup in the device" + recovery__dry_run_verify_remaining_shares = 902, // "Verify remaining recovery shares?" + recovery__enter_each_word = 903, // "Enter each word of your wallet backup in order." + recovery__info_about_disconnect = 904, // "It's safe to disconnect your Trezor while recovering your wallet and continue later." + recovery__share_does_not_match = 905, // "Share doesn't match" + reset__cancel_create_wallet = 906, // "Cancel create wallet" + reset__incorrect_word_selected = 907, // "Incorrect word selected" + reset__more_at = 908, // "More at" + reset__num_of_shares_how_many = 909, // "How many wallet backup shares do you want to create?" + reset__num_of_shares_long_info_template = 910, // "Each backup share is a sequence of {0} words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet." + reset__select_threshold = 911, // "Select the minimum shares required to recover your wallet." + reset__share_completed_template = 912, // "Share #{0} completed" + reset__slip39_checklist_num_shares_x_template = 913, // "Number of shares: {0}" + reset__slip39_checklist_threshold_x_template = 914, // "Recovery threshold: {0}" + send__transaction_signed = 915, // "Transaction signed" + tutorial__continue = 916, // "Continue tutorial" + tutorial__exit = 917, // "Exit tutorial" + tutorial__first_transaction_finish = 918, // "\"\"" + tutorial__first_transaction_intro = 919, // "\"\"" + tutorial__menu = 920, // "Find context-specific actions and options in the menu." + tutorial__one_more_step = 921, // "\"\"" + tutorial__ready_to_use_safe5 = 922, // "You're all set to start using your device!" + tutorial__subtitle_safe5 = 923, // "\"\"" + tutorial__swipe_up_and_down = 924, // "Swipe up & down\nto move through screens." + tutorial__title_easy_navigation = 925, // "Easy navigation" + tutorial__welcome_safe5 = 926, // "Welcome to\nTrezor Safe 5" + words__good_to_know = 927, // "Good to know" + words__operation_cancelled = 928, // "Operation cancelled" + words__settings = 929, // "Settings" + words__try_again = 930, // "Try again." + reset__slip39_checklist_num_groups_x_template = 931, // "Number of groups: {0}" + brightness__title = 932, // "Display brightness" + recovery__title_unlock_repeated_backup = 933, // "Multi-share backup" + recovery__unlock_repeated_backup = 934, // "Create additional backup?" + recovery__unlock_repeated_backup_verb = 935, // "Create backup" + homescreen__set_default = 936, // "Change wallpaper to default image?" + reset__words_may_repeat = 937, // "Words may repeat." + reset__repeat_for_all_shares = 938, // "Repeat for all shares." + homescreen__settings_subtitle = 939, // "Settings" + homescreen__settings_title = 940, // "Homescreen" + reset__the_word_is_repeated = 941, // "The word is repeated" + tutorial__title_lets_begin = 942, // "Let's begin" + tutorial__did_you_know = 943, // "Did you know?" + tutorial__first_wallet = 944, // "The Trezor Model One, created in 2013,\nwas the world's first hardware wallet." + tutorial__restart_tutorial = 945, // "Restart tutorial" + tutorial__title_handy_menu = 946, // "Handy menu" + tutorial__title_hold = 947, // "Hold to confirm important actions" + tutorial__title_well_done = 948, // "Well done!" + tutorial__lets_begin = 949, // "Learn how to use and navigate this device with ease." + tutorial__get_started = 950, // "Get started!" + instructions__swipe_horizontally = 951, // "Swipe horizontally" + setting__adjust = 952, // "Adjust" + setting__apply = 953, // "Apply" + brightness__changed_title = 954, // "Display brightness changed" + brightness__change_title = 955, // "Change display brightness" + words__title_done = 956, // "Done" + reset__slip39_checklist_more_info_threshold = 957, // "The threshold sets the minumum number of shares needed to recover your wallet." + reset__slip39_checklist_more_info_threshold_example_template = 958, // "If you set {0} out of {1} shares, you'll need {2} backup shares to recover your wallet." + passphrase__continue_with_empty_passphrase = 959, // "Continue with empty passphrase?" + #[cfg(feature = "universal_fw")] + fido__more_credentials = 960, // "More credentials" + #[cfg(feature = "universal_fw")] + fido__select_intro = 961, // "Select the credential that you would like to use for authentication." + #[cfg(feature = "universal_fw")] + fido__title_for_authentication = 962, // "for authentication" + #[cfg(feature = "universal_fw")] + fido__title_select_credential = 963, // "Select credential" + instructions__swipe_down = 964, // "Swipe down" + #[cfg(feature = "universal_fw")] + fido__title_credential_details = 965, // "Credential details" } impl TranslatedString { @@ -1251,24 +1381,24 @@ impl TranslatedString { Self::addr_mismatch__wrong_derivation_path => "Wrong derivation path for selected account.", Self::addr_mismatch__xpub_mismatch => "XPUB mismatch?", Self::address__public_key => "Public key", - Self::address__title_cosigner => "COSIGNER", - Self::address__title_receive_address => "RECEIVE ADDRESS", - Self::address__title_yours => "YOURS", - Self::address_details__derivation_path => "Derivation path:", - Self::address_details__title_receive_address => "RECEIVE ADDRESS", - Self::address_details__title_receiving_to => "RECEIVING TO", + Self::address__title_cosigner => "Cosigner", + Self::address__title_receive_address => "Receive address", + Self::address__title_yours => "Yours", + Self::address_details__derivation_path_colon => "Derivation path:", + Self::address_details__title_receive_address => "Receive address", + Self::address_details__title_receiving_to => "Receiving to", Self::authenticate__confirm_template => "Allow connected computer to confirm your {0} is genuine?", Self::authenticate__header => "Authenticate device", - Self::auto_lock__change_template => "Auto-lock your Trezor after {0} of inactivity?", - Self::auto_lock__title => "AUTO-LOCK DELAY", + Self::auto_lock__change_template => "Auto-lock Trezor after {0} of inactivity?", + Self::auto_lock__title => "Auto-lock delay", Self::backup__can_back_up_anytime => "You can back up your Trezor once, at any time.", Self::backup__it_should_be_backed_up => "You should back up your new wallet right now.", Self::backup__it_should_be_backed_up_now => "It should be backed up now!", - Self::backup__new_wallet_created => "New wallet created.\n", - Self::backup__new_wallet_successfully_created => "New wallet created successfully.", + Self::backup__new_wallet_created => "Wallet created.\n", + Self::backup__new_wallet_successfully_created => "Wallet created successfully.", Self::backup__recover_anytime => "You can use your backup to recover your wallet at any time.", - Self::backup__title_backup_wallet => "BACK UP WALLET", - Self::backup__title_skip => "SKIP BACKUP", + Self::backup__title_backup_wallet => "Back up wallet", + Self::backup__title_skip => "Skip backup", Self::backup__want_to_skip => "Are you sure you want to skip the backup?", #[cfg(feature = "universal_fw")] Self::binance__buy => "Buy", @@ -1306,59 +1436,59 @@ impl TranslatedString { Self::bitcoin__new_fee_rate => "New fee rate:", Self::bitcoin__simple_send_of => "Simple send of", Self::bitcoin__ticket_amount => "Ticket amount:", - Self::bitcoin__title_confirm_details => "CONFIRM DETAILS", - Self::bitcoin__title_finalize_transaction => "FINALIZE TRANSACTION", - Self::bitcoin__title_high_mining_fee => "HIGH MINING FEE", - Self::bitcoin__title_meld_transaction => "MELD TRANSACTIONS", - Self::bitcoin__title_modify_amount => "MODIFY AMOUNT", - Self::bitcoin__title_payjoin => "PAYJOIN", - Self::bitcoin__title_proof_of_ownership => "PROOF OF OWNERSHIP", - Self::bitcoin__title_purchase_ticket => "PURCHASE TICKET", - Self::bitcoin__title_update_transaction => "UPDATE TRANSACTION", + Self::bitcoin__title_confirm_details => "Confirm details", + Self::bitcoin__title_finalize_transaction => "Finalize transaction", + Self::bitcoin__title_high_mining_fee => "High mining fee", + Self::bitcoin__title_meld_transaction => "Meld transactions", + Self::bitcoin__title_modify_amount => "Modify amount", + Self::bitcoin__title_payjoin => "Payjoin", + Self::bitcoin__title_proof_of_ownership => "Proof of ownership", + Self::bitcoin__title_purchase_ticket => "Purchase ticket", + Self::bitcoin__title_update_transaction => "Update transaction", Self::bitcoin__unknown_path => "Unknown path", Self::bitcoin__unknown_transaction => "Unknown transaction", Self::bitcoin__unusually_high_fee => "Unusually high fee.", Self::bitcoin__unverified_external_inputs => "The transaction contains unverified external inputs.", Self::bitcoin__valid_signature => "The signature is valid.", Self::bitcoin__voting_rights => "Voting rights to:", - Self::buttons__abort => "ABORT", - Self::buttons__access => "ACCESS", - Self::buttons__again => "AGAIN", - Self::buttons__allow => "ALLOW", - Self::buttons__back => "BACK", - Self::buttons__back_up => "BACK UP", - Self::buttons__cancel => "CANCEL", - Self::buttons__change => "CHANGE", - Self::buttons__check => "CHECK", - Self::buttons__check_again => "CHECK AGAIN", - Self::buttons__close => "CLOSE", - Self::buttons__confirm => "CONFIRM", - Self::buttons__continue => "CONTINUE", - Self::buttons__details => "DETAILS", - Self::buttons__enable => "ENABLE", - Self::buttons__enter => "ENTER", - Self::buttons__enter_share => "ENTER SHARE", - Self::buttons__export => "EXPORT", - Self::buttons__format => "FORMAT", - Self::buttons__go_back => "GO BACK", - Self::buttons__hold_to_confirm => "HOLD TO CONFIRM", - Self::buttons__info => "INFO", - Self::buttons__install => "INSTALL", - Self::buttons__more_info => "MORE INFO", - Self::buttons__ok_i_understand => "OK, I UNDERSTAND", - Self::buttons__purchase => "PURCHASE", - Self::buttons__quit => "QUIT", - Self::buttons__restart => "RESTART", - Self::buttons__retry => "RETRY", - Self::buttons__select => "SELECT", - Self::buttons__set => "SET", - Self::buttons__show_all => "SHOW ALL", - Self::buttons__show_details => "SHOW DETAILS", - Self::buttons__show_words => "SHOW WORDS", - Self::buttons__skip => "SKIP", - Self::buttons__try_again => "TRY AGAIN", - Self::buttons__turn_off => "TURN OFF", - Self::buttons__turn_on => "TURN ON", + Self::buttons__abort => "Abort", + Self::buttons__access => "Access", + Self::buttons__again => "Again", + Self::buttons__allow => "Allow", + Self::buttons__back => "Back", + Self::buttons__back_up => "Back up", + Self::buttons__cancel => "Cancel", + Self::buttons__change => "Change", + Self::buttons__check => "Check", + Self::buttons__check_again => "Check again", + Self::buttons__close => "Close", + Self::buttons__confirm => "Confirm", + Self::buttons__continue => "Continue", + Self::buttons__details => "Details", + Self::buttons__enable => "Enable", + Self::buttons__enter => "Enter", + Self::buttons__enter_share => "Enter share", + Self::buttons__export => "Export", + Self::buttons__format => "Format", + Self::buttons__go_back => "Go back", + Self::buttons__hold_to_confirm => "Hold to confirm", + Self::buttons__info => "Info", + Self::buttons__install => "Install", + Self::buttons__more_info => "More info", + Self::buttons__ok_i_understand => "Ok, I understand", + Self::buttons__purchase => "Purchase", + Self::buttons__quit => "Quit", + Self::buttons__restart => "Restart", + Self::buttons__retry => "Retry", + Self::buttons__select => "Select", + Self::buttons__set => "Set", + Self::buttons__show_all => "Show all", + Self::buttons__show_details => "Show details", + Self::buttons__show_words => "Show words", + Self::buttons__skip => "Skip", + Self::buttons__try_again => "Try again", + Self::buttons__turn_off => "Turn off", + Self::buttons__turn_on => "Turn on", #[cfg(feature = "universal_fw")] Self::cardano__addr_base => "Base", #[cfg(feature = "universal_fw")] @@ -1581,21 +1711,21 @@ impl TranslatedString { Self::coinjoin__do_not_disconnect => "Do not disconnect your Trezor!", Self::coinjoin__max_mining_fee => "Max mining fee", Self::coinjoin__max_rounds => "Max rounds", - Self::coinjoin__title => "AUTHORIZE COINJOIN", - Self::coinjoin__title_do_not_disconnect => "DO NOT DISCONNECT YOUR TREZOR!", - Self::coinjoin__title_progress => "COINJOIN IN PROGRESS", + Self::coinjoin__title => "Authorize coinjoin", + Self::coinjoin__title_do_not_disconnect => "Do not disconnect your trezor!", + Self::coinjoin__title_progress => "Coinjoin in progress", Self::coinjoin__waiting_for_others => "Waiting for others", - Self::confirm_total__fee_rate => "Fee rate:", + Self::confirm_total__fee_rate_colon => "Fee rate:", Self::confirm_total__sending_from_account => "Sending from account:", - Self::confirm_total__title_fee => "FEE INFORMATION", - Self::confirm_total__title_sending_from => "SENDING FROM", + Self::confirm_total__title_fee => "Fee info", + Self::confirm_total__title_sending_from => "Sending from", Self::debug__loading_seed => "Loading seed", Self::debug__loading_seed_not_recommended => "Loading private seed is not recommended.", Self::device_name__change_template => "Change device name to {0}?", - Self::device_name__title => "DEVICE NAME", + Self::device_name__title => "Device name", Self::entropy__send => "Do you really want to send entropy?", - Self::entropy__title => "INTERNAL ENTROPY", - Self::entropy__title_confirm => "CONFIRM ENTROPY", + Self::entropy__title => "\"\"", + Self::entropy__title_confirm => "Confirm entropy", #[cfg(feature = "universal_fw")] Self::eos__about_to_sign_template => "You are about to sign {0}.", #[cfg(feature = "universal_fw")] @@ -1654,8 +1784,7 @@ impl TranslatedString { Self::eos__sell_ram => "Sell RAM", #[cfg(feature = "universal_fw")] Self::eos__sender => "Sender:", - #[cfg(feature = "universal_fw")] - Self::eos__sign_transaction => "Sign transaction", + Self::send__sign_transaction => "Sign transaction", #[cfg(feature = "universal_fw")] Self::eos__threshold => "Threshold:", #[cfg(feature = "universal_fw")] @@ -1683,11 +1812,11 @@ impl TranslatedString { #[cfg(feature = "universal_fw")] Self::ethereum__data_size_template => "Size: {0} bytes", #[cfg(feature = "universal_fw")] - Self::ethereum__gas_limit => "Gas limit:", + Self::ethereum__gas_limit => "Gas limit", #[cfg(feature = "universal_fw")] - Self::ethereum__gas_price => "Gas price:", + Self::ethereum__gas_price => "Gas price", #[cfg(feature = "universal_fw")] - Self::ethereum__max_gas_price => "Max gas price:", + Self::ethereum__max_gas_price => "Max gas price", #[cfg(feature = "universal_fw")] Self::ethereum__name_and_version => "Name and version", #[cfg(feature = "universal_fw")] @@ -1695,7 +1824,7 @@ impl TranslatedString { #[cfg(feature = "universal_fw")] Self::ethereum__no_message_field => "No message field", #[cfg(feature = "universal_fw")] - Self::ethereum__priority_fee => "Priority fee:", + Self::ethereum__priority_fee => "Priority fee", #[cfg(feature = "universal_fw")] Self::ethereum__show_full_array => "Show full array", #[cfg(feature = "universal_fw")] @@ -1707,17 +1836,17 @@ impl TranslatedString { #[cfg(feature = "universal_fw")] Self::ethereum__sign_eip712 => "Really sign EIP-712 typed data?", #[cfg(feature = "universal_fw")] - Self::ethereum__title_confirm_data => "CONFIRM DATA", + Self::ethereum__title_confirm_data => "Confirm data", #[cfg(feature = "universal_fw")] - Self::ethereum__title_confirm_domain => "CONFIRM DOMAIN", + Self::ethereum__title_confirm_domain => "Confirm domain", #[cfg(feature = "universal_fw")] - Self::ethereum__title_confirm_message => "CONFIRM MESSAGE", + Self::ethereum__title_confirm_message => "Confirm message", #[cfg(feature = "universal_fw")] - Self::ethereum__title_confirm_struct => "CONFIRM STRUCT", + Self::ethereum__title_confirm_struct => "Confirm struct", #[cfg(feature = "universal_fw")] - Self::ethereum__title_confirm_typed_data => "CONFIRM TYPED DATA", + Self::ethereum__title_confirm_typed_data => "Confirm typed data", #[cfg(feature = "universal_fw")] - Self::ethereum__title_signing_address => "SIGNING ADDRESS", + Self::ethereum__title_signing_address => "Signing address", #[cfg(feature = "universal_fw")] Self::ethereum__units_template => "{0} units", #[cfg(feature = "universal_fw")] @@ -1726,7 +1855,7 @@ impl TranslatedString { Self::ethereum__valid_signature => "The signature is valid.", Self::experimental_mode__enable => "Enable experimental features?", Self::experimental_mode__only_for_dev => "Only for development and beta testing!", - Self::experimental_mode__title => "EXPERIMENTAL MODE", + Self::experimental_mode__title => "Experimental mode", #[cfg(feature = "universal_fw")] Self::fido__already_registered => "Already registered", #[cfg(feature = "universal_fw")] @@ -1748,39 +1877,39 @@ impl TranslatedString { #[cfg(feature = "universal_fw")] Self::fido__please_enable_pin_protection => "Please enable PIN protection.", #[cfg(feature = "universal_fw")] - Self::fido__title_authenticate => "FIDO2 AUTHENTICATE", + Self::fido__title_authenticate => "FIDO2 authenticate", #[cfg(feature = "universal_fw")] - Self::fido__title_import_credential => "IMPORT CREDENTIAL", + Self::fido__title_import_credential => "Import credential", #[cfg(feature = "universal_fw")] - Self::fido__title_list_credentials => "LIST CREDENTIALS", + Self::fido__title_list_credentials => "List credentials", #[cfg(feature = "universal_fw")] - Self::fido__title_register => "FIDO2 REGISTER", + Self::fido__title_register => "FIDO2 register", #[cfg(feature = "universal_fw")] - Self::fido__title_remove_credential => "REMOVE CREDENTIAL", + Self::fido__title_remove_credential => "Remove credential", #[cfg(feature = "universal_fw")] - Self::fido__title_reset => "FIDO2 RESET", + Self::fido__title_reset => "FIDO2 reset", #[cfg(feature = "universal_fw")] - Self::fido__title_u2f_auth => "U2F AUTHENTICATE", + Self::fido__title_u2f_auth => "U2F authenticate", #[cfg(feature = "universal_fw")] - Self::fido__title_u2f_register => "U2F REGISTER", + Self::fido__title_u2f_register => "U2F register", #[cfg(feature = "universal_fw")] - Self::fido__title_verify_user => "FIDO2 VERIFY USER", + Self::fido__title_verify_user => "FIDO2 verify user", #[cfg(feature = "universal_fw")] Self::fido__unable_to_verify_user => "Unable to verify user.", #[cfg(feature = "universal_fw")] Self::fido__wanna_erase_credentials => "Do you really want to erase all credentials?", - Self::firmware_update__title => "UPDATE FIRMWARE", - Self::firmware_update__title_fingerprint => "FW FINGERPRINT", + Self::firmware_update__title => "Update firmware", + Self::firmware_update__title_fingerprint => "FW fingerprint", Self::homescreen__click_to_connect => "Click to Connect", Self::homescreen__click_to_unlock => "Click to Unlock", - Self::homescreen__title_backup_failed => "BACKUP FAILED", - Self::homescreen__title_backup_needed => "BACKUP NEEDED", - Self::homescreen__title_coinjoin_authorized => "COINJOIN AUTHORIZED", - Self::homescreen__title_experimental_mode => "EXPERIMENTAL MODE", - Self::homescreen__title_no_usb_connection => "NO USB CONNECTION", - Self::homescreen__title_pin_not_set => "PIN NOT SET", - Self::homescreen__title_seedless => "SEEDLESS", - Self::homescreen__title_set => "CHANGE HOMESCREEN?", + Self::homescreen__title_backup_failed => "Backup failed", + Self::homescreen__title_backup_needed => "Backup needed", + Self::homescreen__title_coinjoin_authorized => "Coinjoin authorized", + Self::homescreen__title_experimental_mode => "Experimental mode", + Self::homescreen__title_no_usb_connection => "No USB connection", + Self::homescreen__title_pin_not_set => "PIN not set", + Self::homescreen__title_seedless => "Seedless", + Self::homescreen__title_set => "Change wallpaper", Self::inputs__back => "BACK", Self::inputs__cancel => "CANCEL", Self::inputs__delete => "DELETE", @@ -1788,30 +1917,30 @@ impl TranslatedString { Self::inputs__return => "RETURN", Self::inputs__show => "SHOW", Self::inputs__space => "SPACE", - Self::joint__title => "JOINT TRANSACTION", + Self::joint__title => "Joint transaction", Self::joint__to_the_total_amount => "To the total amount:", Self::joint__you_are_contributing => "You are contributing:", Self::language__change_to_template => "Change language to {0}?", Self::language__changed => "Language changed successfully", Self::language__progress => "Changing language", - Self::language__title => "LANGUAGE SETTINGS", + Self::language__title => "Language settings", Self::lockscreen__tap_to_connect => "Tap to connect", Self::lockscreen__tap_to_unlock => "Tap to unlock", - Self::lockscreen__title_locked => "LOCKED", - Self::lockscreen__title_not_connected => "NOT CONNECTED", + Self::lockscreen__title_locked => "Locked", + Self::lockscreen__title_not_connected => "Not connected", Self::misc__decrypt_value => "Decrypt value", Self::misc__encrypt_value => "Encrypt value", - Self::misc__title_suite_labeling => "SUITE LABELING", + Self::misc__title_suite_labeling => "Suite labeling", Self::modify_amount__decrease_amount => "Decrease amount by:", Self::modify_amount__increase_amount => "Increase amount by:", Self::modify_amount__new_amount => "New amount:", - Self::modify_amount__title => "MODIFY AMOUNT", + Self::modify_amount__title => "Modify amount", Self::modify_fee__decrease_fee => "Decrease fee by:", Self::modify_fee__fee_rate => "Fee rate:", Self::modify_fee__increase_fee => "Increase fee by:", Self::modify_fee__new_transaction_fee => "New transaction fee:", Self::modify_fee__no_change => "Fee did not change.\n", - Self::modify_fee__title => "MODIFY FEE", + Self::modify_fee__title => "Modify fee", Self::modify_fee__transaction_fee => "Transaction fee:", #[cfg(feature = "universal_fw")] Self::monero__confirm_export => "Confirm export", @@ -1951,19 +2080,19 @@ impl TranslatedString { Self::nem__unencrypted => "Unencrypted:", #[cfg(feature = "universal_fw")] Self::nem__unknown_mosaic => "Unknown mosaic!", - Self::passphrase__access_hidden_wallet => "Access hidden wallet?", - Self::passphrase__always_on_device => "Do you really want to enter passphrase always on the device?", + Self::passphrase__access_wallet => "Access passphrase wallet?", + Self::passphrase__always_on_device => "Always enter your passphrase on Trezor?", Self::passphrase__from_host_not_shown => "Passphrase provided by host will be used but will not be displayed due to the device settings.", - Self::passphrase__hidden_wallet => "Hidden wallet", + Self::passphrase__wallet => "Passphrase wallet", Self::passphrase__hide => "Hide passphrase coming from host?", - Self::passphrase__next_screen_will_show_passphrase => "Next screen will show the passphrase.", + Self::passphrase__next_screen_will_show_passphrase => "The next screen shows your passphrase.", Self::passphrase__please_enter => "Please enter your passphrase.", Self::passphrase__revoke_on_device => "Do you want to revoke the passphrase on device setting?", - Self::passphrase__title_confirm => "CONFIRM PASSPHRASE", - Self::passphrase__title_enter => "ENTER PASSPHRASE", - Self::passphrase__title_hide => "HIDE PASSPHRASE", - Self::passphrase__title_settings => "PASSPHRASE SETTINGS", - Self::passphrase__title_source => "PASSPHRASE SOURCE", + Self::passphrase__title_confirm => "Confirm passphrase", + Self::passphrase__title_enter => "Enter passphrase", + Self::passphrase__title_hide => "Hide passphrase", + Self::passphrase__title_settings => "Passphrase settings", + Self::passphrase__title_source => "Passphrase source", Self::passphrase__turn_off => "Turn off passphrase protection?", Self::passphrase__turn_on => "Turn on passphrase protection?", Self::pin__change => "Change PIN?", @@ -1984,9 +2113,9 @@ impl TranslatedString { Self::pin__reenter_new => "Re-enter new PIN", Self::pin__reenter_to_confirm => "Please re-enter PIN to confirm.", Self::pin__should_be_long => "PIN should be 4-50 digits long.", - Self::pin__title_check_pin => "CHECK PIN", - Self::pin__title_settings => "PIN SETTINGS", - Self::pin__title_wrong_pin => "WRONG PIN", + Self::pin__title_check_pin => "Check PIN", + Self::pin__title_settings => "PIN settings", + Self::pin__title_wrong_pin => "Wrong PIN", Self::pin__tries_left => "tries left", Self::pin__turn_off => "Are you sure you want to turn off PIN protection?", Self::pin__turn_on => "Turn on PIN protection?", @@ -2005,25 +2134,25 @@ impl TranslatedString { Self::progress__loading_transaction => "Loading transaction...", Self::progress__locking_device => "Locking the device...", Self::progress__one_second_left => "1 second left", - Self::progress__please_wait => "PLEASE WAIT", - Self::storage_msg__processing => "PROCESSING", + Self::progress__please_wait => "Please wait", + Self::storage_msg__processing => "Processing", Self::progress__refreshing => "Refreshing...", Self::progress__signing_transaction => "Signing transaction...", Self::progress__syncing => "Syncing...", Self::progress__x_seconds_left_template => "{0} seconds left", Self::reboot_to_bootloader__restart => "Trezor will restart in bootloader mode.", - Self::reboot_to_bootloader__title => "GO TO BOOTLOADER", + Self::reboot_to_bootloader__title => "Go to bootloader", Self::reboot_to_bootloader__version_by_template => "Firmware version {0}\nby {1}", Self::recovery__cancel_dry_run => "Cancel backup check", Self::recovery__check_dry_run => "Check your backup?", Self::recovery__cursor_will_change => "Position of the cursor will change between entries for enhanced security.", - Self::recovery__dry_run_bip39_valid_match => "The entered recovery wallet backup is valid and matches the one in the device.", + Self::recovery__dry_run_bip39_valid_match => "The entered wallet backup is valid and matches the one in this device.", Self::recovery__dry_run_bip39_valid_mismatch => "The entered wallet backup is valid but does not match the one in the device.", Self::recovery__dry_run_slip39_valid_match => "The entered recovery shares are valid and match what is currently in the device.", Self::recovery__dry_run_slip39_valid_mismatch => "The entered recovery shares are valid but do not match what is currently in the device.", Self::recovery__enter_any_share => "Enter any share", Self::recovery__enter_backup => "Enter your backup.", - Self::recovery__enter_different_share => "Please enter a different share.", + Self::recovery__enter_different_share => "Enter a different share.", Self::recovery__enter_share_from_diff_group => "Enter share from a different group.", Self::recovery__group_num_template => "Group {0}", Self::recovery__group_threshold_reached => "Group threshold reached.", @@ -2033,36 +2162,36 @@ impl TranslatedString { Self::recovery__num_of_words => "Select the number of words in your backup.", Self::recovery__only_first_n_letters => "You'll only have to select the first 2-4 letters of each word.", Self::recovery__progress_will_be_lost => "All progress will be lost.", - Self::recovery__select_num_of_words => "Select the number of words in your backup.", + Self::recovery__select_num_of_words => "\"\"", Self::recovery__share_already_entered => "Share already entered", - Self::recovery__share_from_another_shamir => "You have entered a share from another Shamir Backup.", + Self::recovery__share_from_another_multi_share_backup => "You have entered a share from a different backup.", Self::recovery__share_num_template => "Share {0}", - Self::recovery__title => "RECOVER WALLET", - Self::recovery__title_cancel_dry_run => "CANCEL BACKUP CHECK", - Self::recovery__title_cancel_recovery => "CANCEL RECOVERY", - Self::recovery__title_dry_run => "BACKUP CHECK", - Self::recovery__title_recover => "RECOVER WALLET", - Self::recovery__title_remaining_shares => "REMAINING SHARES", + Self::recovery__title => "Recover wallet", + Self::recovery__title_cancel_dry_run => "Cancel backup check", + Self::recovery__title_cancel_recovery => "Cancel recovery", + Self::recovery__title_dry_run => "Backup check", + Self::recovery__title_recover => "Recover wallet", + Self::recovery__title_remaining_shares => "Remaining shares", Self::recovery__type_word_x_of_y_template => "Type word {0} of {1}", - Self::recovery__wallet_recovered => "Wallet recovered successfully", + Self::recovery__wallet_recovered => "Wallet recovery completed", Self::recovery__wanna_cancel_dry_run => "Are you sure you want to cancel the backup check?", Self::recovery__wanna_cancel_recovery => "Are you sure you want to cancel the recovery process?", Self::recovery__word_count_template => "({0} words)", - Self::recovery__word_x_of_y_template => "WORD {0} OF {1}", + Self::recovery__word_x_of_y_template => "Word {0} of {1}", Self::recovery__x_more_items_starting_template_plural => "{count} more {plural} starting", - Self::recovery__x_more_shares_needed_template_plural => "{count} more {plural} needed.", - Self::recovery__x_of_y_entered_template => "{0} of {1} shares entered successfully.", + Self::recovery__x_more_shares_needed_template_plural => "{count} more {plural} needed", + Self::recovery__x_of_y_entered_template => "{0} of {1} shares entered", Self::recovery__you_have_entered => "You have entered", Self::reset__advanced_group_threshold_info => "The group threshold specifies the number of groups required to recover your wallet.", Self::reset__all_x_of_y_template => "all {0} of {1} shares", Self::reset__any_x_of_y_template => "any {0} of {1} shares", - Self::reset__button_create => "CREATE WALLET", - Self::reset__button_recover => "RECOVER WALLET", + Self::reset__button_create => "Create wallet", + Self::reset__button_recover => "Recover wallet", Self::reset__by_continuing => "By continuing you agree to Trezor Company's terms and conditions.", - Self::reset__check_backup_title => "CHECK BACKUP", - Self::reset__check_group_share_title_template => "CHECK G{0} - SHARE {1}", - Self::reset__check_wallet_backup_title => "CHECK WALLET BACKUP", - Self::reset__check_share_title_template => "CHECK SHARE #{0}", + Self::reset__check_backup_title => "Check backup", + Self::reset__check_group_share_title_template => "Check g{0} - share {1}", + Self::reset__check_wallet_backup_title => "Check wallet backup", + Self::reset__check_share_title_template => "Check share #{0}", Self::reset__continue_with_next_share => "Continue with the next share.", Self::reset__continue_with_share_template => "Continue with share #{0}.", Self::reset__finished_verifying_group_template => "You have finished verifying your recovery shares for group {0}.", @@ -2071,7 +2200,7 @@ impl TranslatedString { Self::reset__group_description => "A group is made up of recovery shares.", Self::reset__group_info => "Each group has a set number of shares and its own threshold. In the next steps you will set the numbers of shares and the thresholds.", Self::reset__group_share_checked_successfully_template => "Group {0} - Share {1} checked successfully.", - Self::reset__group_share_title_template => "GROUP {0} - SHARE {1}", + Self::reset__group_share_title_template => "Group {0} - share {1}", Self::reset__more_info_at => "More info at", Self::reset__need_all_share_template => "For recovery you need all {0} of the shares.", Self::reset__need_any_share_template => "For recovery you need any {0} of the shares.", @@ -2079,21 +2208,21 @@ impl TranslatedString { Self::reset__needed_to_recover_your_wallet => "needed to recover your wallet. ", Self::reset__never_make_digital_copy => "Never put your backup anywhere digital.", Self::reset__num_of_share_holders_template => "{0} people or locations will each hold one share.", - Self::reset__num_of_shares_advanced_info_template => "Each recovery share is a sequence of 20 words. Next you will choose the threshold number of shares needed to form Group {0}.", - Self::reset__num_of_shares_basic_info => "Each recovery share is a sequence of 20 words. Next you will choose how many shares you need to recover your wallet.", + Self::reset__num_of_shares_advanced_info_template => "Each recovery share is a sequence of {0} words. Next you will choose the threshold number of shares needed to form Group {1}.", + Self::reset__num_of_shares_basic_info_template => "Each recovery share is a sequence of {0} words. Next you will choose how many shares you need to recover your wallet.", Self::reset__num_shares_for_group_template => "The required number of shares to form Group {0}.", Self::reset__number_of_shares_info => "= total number of unique word lists used for wallet backup.", Self::reset__one_share => "1 share", Self::reset__only_one_share_will_be_created => "Only one share will be created.", - Self::reset__recovery_wallet_backup_title => "WALLET BACKUP", - Self::reset__recovery_share_title_template => "RECOVERY SHARE #{0}", + Self::reset__recovery_wallet_backup_title => "Wallet backup", + Self::reset__recovery_share_title_template => "Recovery share #{0}", Self::reset__required_number_of_groups => "The required number of groups for recovery.", Self::reset__select_correct_word => "Select the correct word for each position.", - Self::reset__select_word_template => "SELECT {0} WORD", + Self::reset__select_word_template => "Select {0} word", Self::reset__select_word_x_of_y_template => "Select word {0} of {1}:", Self::reset__set_it_to_count_template => "Set it to {0} and you will need ", - Self::reset__share_checked_successfully_template => "Recovery share #{0} checked successfully.", - Self::reset__share_words_title => "STANDARD BACKUP", + Self::reset__share_checked_successfully_template => "Share #{0} checked successfully.", + Self::reset__share_words_title => "Standard backup", Self::reset__slip39_checklist_num_groups => "Number of groups", Self::reset__slip39_checklist_num_shares => "Number of shares", Self::reset__slip39_checklist_set_num_groups => "Set number of groups", @@ -2101,26 +2230,26 @@ impl TranslatedString { Self::reset__slip39_checklist_set_sizes => "Set sizes and thresholds", Self::reset__slip39_checklist_set_sizes_longer => "Set size and threshold for each group", Self::reset__slip39_checklist_set_threshold => "Set threshold", - Self::reset__slip39_checklist_title => "BACKUP CHECKLIST", + Self::reset__slip39_checklist_title => "Backup checklist", Self::reset__slip39_checklist_write_down => "Write down and check all shares", - Self::reset__slip39_checklist_write_down_recovery => "Write down and check all recovery shares", + Self::reset__slip39_checklist_write_down_recovery => "Write down & check all wallet backup shares", Self::reset__the_threshold_sets_the_number_of_shares => "The threshold sets the number of shares ", Self::reset__threshold_info => "= minimum number of unique word lists used for recovery.", - Self::reset__title_backup_is_done => "BACKUP IS DONE", - Self::reset__title_create_wallet => "CREATE WALLET", - Self::reset__title_create_wallet_shamir => "CREATE WALLET (SHAMIR)", - Self::reset__title_group_threshold => "GROUP THRESHOLD", - Self::reset__title_number_of_groups => "NUMBER OF GROUPS", - Self::reset__title_number_of_shares => "NUMBER OF SHARES", - Self::reset__title_set_group_threshold => "SET GROUP THRESHOLD", - Self::reset__title_set_number_of_groups => "SET NUMBER OF GROUPS", - Self::reset__title_set_number_of_shares => "SET NUMBER OF SHARES", - Self::reset__title_set_threshold => "SET THRESHOLD", + Self::reset__title_backup_is_done => "Backup is done", + Self::reset__title_create_wallet => "Create wallet", + Self::reset__title_create_wallet_shamir => "\"\"", + Self::reset__title_group_threshold => "Group threshold", + Self::reset__title_number_of_groups => "Number of groups", + Self::reset__title_number_of_shares => "Number of shares", + Self::reset__title_set_group_threshold => "Set group threshold", + Self::reset__title_set_number_of_groups => "Set number of groups", + Self::reset__title_set_number_of_shares => "Set number of shares", + Self::reset__title_set_threshold => "Set threshold", Self::reset__to_form_group_template => "to form Group {0}.", Self::reset__tos_link => "trezor.io/tos", Self::reset__total_number_of_shares_in_group_template => "Set the total number of shares in Group {0}.", Self::reset__use_your_backup => "Use your backup when you need to recover your wallet.", - Self::reset__write_down_words_template => "Write down all {0} words in order.", + Self::reset__write_down_words_template => "Write the following {0} words in order on your wallet backup card.", Self::reset__wrong_word_selected => "Wrong word selected!", Self::reset__you_need_one_share => "For recovery you need 1 share.", Self::reset__your_backup_is_done => "Your backup is done.", @@ -2132,13 +2261,13 @@ impl TranslatedString { Self::rotation__east => "east", Self::rotation__north => "north", Self::rotation__south => "south", - Self::rotation__title_change => "CHANGE ROTATION", + Self::rotation__title_change => "Change rotation", Self::rotation__west => "west", Self::safety_checks__approve_unsafe_always => "Trezor will allow you to approve some actions which might be unsafe.", Self::safety_checks__approve_unsafe_temporary => "Trezor will temporarily allow you to approve some actions which might be unsafe.", Self::safety_checks__enforce_strict => "Do you really want to enforce strict safety checks (recommended)?", - Self::safety_checks__title => "SAFETY CHECKS", - Self::safety_checks__title_safety_override => "SAFETY OVERRIDE", + Self::safety_checks__title => "Safety checks", + Self::safety_checks__title_safety_override => "Safety override", Self::sd_card__all_data_will_be_lost => "All data on the SD card will be lost.", Self::sd_card__card_required => "SD card required.", Self::sd_card__disable => "Do you really want to remove SD card protection from your device?", @@ -2154,36 +2283,36 @@ impl TranslatedString { Self::sd_card__refresh => "Do you really want to replace the current SD card secret with a newly generated one?", Self::sd_card__refreshed => "You have successfully refreshed SD protection.", Self::sd_card__restart => "Do you want to restart Trezor in bootloader mode?", - Self::sd_card__title => "SD CARD PROTECTION", - Self::sd_card__title_problem => "SD CARD PROBLEM", + Self::sd_card__title => "SD card protection", + Self::sd_card__title_problem => "SD card problem", Self::sd_card__unknown_filesystem => "Unknown filesystem.", Self::sd_card__unplug_and_insert_correct => "Please unplug the device and insert the correct SD card.", Self::sd_card__use_different_card => "Use a different card or format the SD card to the FAT32 filesystem.", Self::sd_card__wanna_format => "Do you really want to format the SD card?", Self::sd_card__wrong_sd_card => "Wrong SD card.", Self::send__address_path => "address path", - Self::send__confirm_sending => "SENDING AMOUNT", + Self::send__confirm_sending => "Sending amount", Self::send__from_multiple_accounts => "Sending from multiple accounts.", Self::send__including_fee => "Including fee:", - Self::send__maximum_fee => "Maximum fee:", + Self::send__maximum_fee => "Maximum fee", Self::send__receiving_to_multisig => "Receiving to a multisig address.", - Self::send__title_confirm_sending => "CONFIRM SENDING", - Self::send__title_joint_transaction => "JOINT TRANSACTION", - Self::send__title_receiving_to => "RECEIVING TO", - Self::send__title_sending => "SENDING", - Self::send__title_sending_amount => "SENDING AMOUNT", - Self::send__title_sending_to => "SENDING TO", + Self::send__title_confirm_sending => "Confirm sending", + Self::send__title_joint_transaction => "Joint transaction", + Self::send__title_receiving_to => "Receiving to", + Self::send__title_sending => "Sending", + Self::send__title_sending_amount => "Sending amount", + Self::send__title_sending_to => "Sending to", Self::send__to_the_total_amount => "To the total amount:", - Self::send__total_amount => "Total amount:", + Self::send__total_amount_colon => "Total amount:", Self::send__transaction_id => "Transaction ID:", Self::send__you_are_contributing => "You are contributing:", Self::share_words__words_in_order => " words in order.", Self::share_words__wrote_down_all => "I wrote down all ", Self::sign_message__bytes_template => "{0} Bytes", - Self::sign_message__confirm_address => "SIGNING ADDRESS", - Self::sign_message__confirm_message => "CONFIRM MESSAGE", + Self::sign_message__confirm_address => "Signing address", + Self::sign_message__confirm_message => "Confirm message", Self::sign_message__message_size => "Message size:", - Self::sign_message__verify_address => "VERIFY ADDRESS", + Self::sign_message__verify_address => "Verify address", #[cfg(feature = "universal_fw")] Self::solana__account_index => "Account index", #[cfg(feature = "universal_fw")] @@ -2375,10 +2504,10 @@ impl TranslatedString { Self::tutorial__ready_to_use => "You're ready to\nuse Trezor.", Self::tutorial__scroll_down => "Press right to scroll down to read all content when text doesn't fit on one screen.\n\rPress left to scroll up.", Self::tutorial__sure_you_want_skip => "Are you sure you\nwant to skip the tutorial?", - Self::tutorial__title_hello => "HELLO", - Self::tutorial__title_screen_scroll => "SCREEN SCROLL", - Self::tutorial__title_skip => "SKIP TUTORIAL", - Self::tutorial__title_tutorial_complete => "TUTORIAL COMPLETE", + Self::tutorial__title_hello => "Hello", + Self::tutorial__title_screen_scroll => "Screen scroll", + Self::tutorial__title_skip => "Skip tutorial", + Self::tutorial__title_tutorial_complete => "Tutorial complete", Self::tutorial__use_trezor => "Use Trezor by\nclicking the left and right buttons.\n\rContinue right.", Self::tutorial__welcome_press_right => "Welcome to Trezor. Press right to continue.", #[cfg(feature = "universal_fw")] @@ -2386,11 +2515,11 @@ impl TranslatedString { #[cfg(feature = "universal_fw")] Self::u2f__set_template => "Set the U2F counter to {0}?", #[cfg(feature = "universal_fw")] - Self::u2f__title_get => "GET U2F COUNTER", + Self::u2f__title_get => "Get U2F counter", #[cfg(feature = "universal_fw")] - Self::u2f__title_set => "SET U2F COUNTER", + Self::u2f__title_set => "Set U2F counter", Self::wipe__info => "All data will be erased.", - Self::wipe__title => "WIPE DEVICE", + Self::wipe__title => "Wipe device", Self::wipe__want_to_wipe => "Do you really want to wipe the device?\n", Self::wipe_code__change => "Change wipe code?", Self::wipe_code__changed => "Wipe code changed.", @@ -2403,13 +2532,13 @@ impl TranslatedString { Self::wipe_code__mismatch => "The wipe codes you entered do not match.", Self::wipe_code__reenter => "Re-enter wipe code", Self::wipe_code__reenter_to_confirm => "Please re-enter wipe code to confirm.", - Self::wipe_code__title_check => "CHECK WIPE CODE", - Self::wipe_code__title_invalid => "INVALID WIPE CODE", - Self::wipe_code__title_settings => "WIPE CODE SETTINGS", + Self::wipe_code__title_check => "Check wipe code", + Self::wipe_code__title_invalid => "Invalid wipe code", + Self::wipe_code__title_settings => "Wipe code settings", Self::wipe_code__turn_off => "Turn off wipe code protection?", Self::wipe_code__turn_on => "Turn on wipe code protection?", Self::wipe_code__wipe_code_mismatch => "Wipe code mismatch", - Self::word_count__title => "NUMBER OF WORDS", + Self::word_count__title => "Number of words", Self::words__account => "Account", Self::words__account_colon => "Account:", Self::words__address => "Address", @@ -2437,15 +2566,15 @@ impl TranslatedString { Self::words__recipient => "Recipient", Self::words__sign => "Sign", Self::words__signer => "Signer", - Self::words__title_check => "CHECK", - Self::words__title_group => "GROUP", - Self::words__title_information => "INFORMATION", - Self::words__title_remember => "REMEMBER", - Self::words__title_share => "SHARE", - Self::words__title_shares => "SHARES", - Self::words__title_success => "SUCCESS", - Self::words__title_summary => "SUMMARY", - Self::words__title_threshold => "THRESHOLD", + Self::words__title_check => "Check", + Self::words__title_group => "Group", + Self::words__title_information => "Information", + Self::words__title_remember => "Remember", + Self::words__title_share => "Share", + Self::words__title_shares => "Shares", + Self::words__title_success => "Success", + Self::words__title_summary => "Summary", + Self::words__title_threshold => "Threshold", Self::words__unknown => "Unknown", Self::words__warning => "Warning", Self::words__writable => "Writable", @@ -2453,26 +2582,156 @@ impl TranslatedString { Self::reboot_to_bootloader__just_a_moment => "Just a moment...", Self::inputs__previous => "PREVIOUS", #[cfg(feature = "universal_fw")] - Self::ethereum__staking_claim => "CLAIM", + Self::ethereum__staking_claim => "Claim", #[cfg(feature = "universal_fw")] - Self::ethereum__staking_claim_address => "CLAIM ADDRESS", + Self::ethereum__staking_claim_address => "Claim address", #[cfg(feature = "universal_fw")] Self::ethereum__staking_claim_intro => "Claim ETH from Everstake?", #[cfg(feature = "universal_fw")] - Self::ethereum__staking_stake => "STAKE", + Self::ethereum__staking_stake => "Stake", #[cfg(feature = "universal_fw")] - Self::ethereum__staking_stake_address => "STAKE ADDRESS", + Self::ethereum__staking_stake_address => "Stake address", #[cfg(feature = "universal_fw")] Self::ethereum__staking_stake_intro => "Stake ETH on Everstake?", #[cfg(feature = "universal_fw")] - Self::ethereum__staking_unstake => "UNSTAKE", + Self::ethereum__staking_unstake => "Unstake", #[cfg(feature = "universal_fw")] Self::ethereum__staking_unstake_intro => "Unstake ETH from Everstake?", - Self::storage_msg__starting => "STARTING UP", - Self::storage_msg__verifying_pin => "VERIFYING PIN", - Self::storage_msg__wrong_pin => "WRONG PIN", - Self::reset__create_x_of_y_shamir_backup_template => "Do you want to create a {0} of {1} Shamir backup?", - Self::reset__title_shamir_backup => "SHAMIR BACKUP", + Self::storage_msg__starting => "Starting up", + Self::storage_msg__verifying_pin => "Verifying PIN", + Self::storage_msg__wrong_pin => "Wrong PIN", + Self::reset__create_x_of_y_multi_share_backup_template => "Do you want to create a {0} of {1} multi-share backup?", + Self::reset__title_shamir_backup => "Multi-share backup", + #[cfg(feature = "universal_fw")] + Self::cardano__always_abstain => "Always Abstain", + #[cfg(feature = "universal_fw")] + Self::cardano__always_no_confidence => "Always No Confidence", + #[cfg(feature = "universal_fw")] + Self::cardano__delegating_to_key_hash => "Delegating to key hash:", + #[cfg(feature = "universal_fw")] + Self::cardano__delegating_to_script => "Delegating to script:", + #[cfg(feature = "universal_fw")] + Self::cardano__deposit => "Deposit:", + #[cfg(feature = "universal_fw")] + Self::cardano__vote_delegation => "Vote delegation", + Self::instructions__swipe_up => "Swipe up", + Self::instructions__tap_to_confirm => "Tap to confirm", + Self::instructions__hold_to_confirm => "Hold to confirm", + Self::words__important => "Important", + Self::reset__words_written_down_template => "I wrote down all {0} words in order.", + Self::backup__create_backup_to_prevent_loss => "Create a backup to avoid losing access to your funds", + Self::reset__check_backup_instructions => "Let's do a quick check of your backup.", + Self::words__instructions => "Instructions", + Self::words__not_recommended => "Not recommended!", + Self::address_details__account_info => "Account info", + Self::address__cancel_contact_support => "If receive address doesn't match, contact Trezor Support at trezor.io/support.", + Self::address__cancel_receive => "Cancel receive", + Self::address__qr_code => "QR code", + Self::address_details__derivation_path => "Derivation path", + Self::instructions__continue_in_app => "Continue in the app", + Self::words__cancel_and_exit => "Cancel and exit", + Self::address__confirmed => "Receive address confirmed", + Self::pin__cancel_description => "Continue without PIN", + Self::pin__cancel_info => "Without a PIN, anyone can access this device.", + Self::pin__cancel_setup => "Cancel PIN setup", + Self::send__cancel_sign => "Cancel sign", + Self::send__send_from => "Send from", + Self::instructions__hold_to_sign => "Hold to sign", + Self::confirm_total__fee_rate => "Fee rate", + Self::send__incl_transaction_fee => "incl. Transaction fee", + Self::send__total_amount => "Total amount", + Self::auto_lock__turned_on => "Auto-lock turned on", + Self::backup__info_multi_share_backup => "Your wallet backup contains multiple lists of words in a specific order (shares).", + Self::backup__info_single_share_backup => "Your wallet backup contains {0} words in a specific order.", + Self::backup__title_backup_completed => "Wallet backup completed", + Self::backup__title_create_wallet_backup => "Create wallet backup", + Self::haptic_feedback__disable => "Disable haptic feedback?", + Self::haptic_feedback__enable => "Enable haptic feedback?", + Self::haptic_feedback__subtitle => "Setting", + Self::haptic_feedback__title => "Haptic feedback", + Self::instructions__continue_holding => "Continue\nholding", + Self::instructions__enter_next_share => "Enter next share", + Self::instructions__hold_to_continue => "Hold to continue", + Self::instructions__hold_to_exit_tutorial => "Hold to exit tutorial", + Self::instructions__hold_to_finish_tutorial => "\"\"", + Self::instructions__learn_more => "Learn more", + Self::instructions__shares_continue_with_x_template => "Continue with Share #{0}", + Self::instructions__shares_start_with_1 => "Start with share #1", + Self::instructions__tap_to_start => "Tap to start", + Self::passphrase__title_passphrase => "Passphrase", + Self::recovery__dry_run_backup_not_on_this_device => "Wallet backup not on this device", + Self::recovery__dry_run_invalid_backup_entered => "Invalid wallet backup entered", + Self::recovery__dry_run_slip39_valid_all_shares => "All shares are valid and belong to the backup in this device", + Self::recovery__dry_run_slip39_valid_share => "Entered share is valid and belongs to the backup in the device", + Self::recovery__dry_run_verify_remaining_shares => "Verify remaining recovery shares?", + Self::recovery__enter_each_word => "Enter each word of your wallet backup in order.", + Self::recovery__info_about_disconnect => "It's safe to disconnect your Trezor while recovering your wallet and continue later.", + Self::recovery__share_does_not_match => "Share doesn't match", + Self::reset__cancel_create_wallet => "Cancel create wallet", + Self::reset__incorrect_word_selected => "Incorrect word selected", + Self::reset__more_at => "More at", + Self::reset__num_of_shares_how_many => "How many wallet backup shares do you want to create?", + Self::reset__num_of_shares_long_info_template => "Each backup share is a sequence of {0} words. Store each wordlist in a separate, safe location or share with trusted individuals. Collect as needed to recover your wallet.", + Self::reset__select_threshold => "Select the minimum shares required to recover your wallet.", + Self::reset__share_completed_template => "Share #{0} completed", + Self::reset__slip39_checklist_num_shares_x_template => "Number of shares: {0}", + Self::reset__slip39_checklist_threshold_x_template => "Recovery threshold: {0}", + Self::send__transaction_signed => "Transaction signed", + Self::tutorial__continue => "Continue tutorial", + Self::tutorial__exit => "Exit tutorial", + Self::tutorial__first_transaction_finish => "\"\"", + Self::tutorial__first_transaction_intro => "\"\"", + Self::tutorial__menu => "Find context-specific actions and options in the menu.", + Self::tutorial__one_more_step => "\"\"", + Self::tutorial__ready_to_use_safe5 => "You're all set to start using your device!", + Self::tutorial__subtitle_safe5 => "\"\"", + Self::tutorial__swipe_up_and_down => "Swipe up & down\nto move through screens.", + Self::tutorial__title_easy_navigation => "Easy navigation", + Self::tutorial__welcome_safe5 => "Welcome to\nTrezor Safe 5", + Self::words__good_to_know => "Good to know", + Self::words__operation_cancelled => "Operation cancelled", + Self::words__settings => "Settings", + Self::words__try_again => "Try again.", + Self::reset__slip39_checklist_num_groups_x_template => "Number of groups: {0}", + Self::brightness__title => "Display brightness", + Self::recovery__title_unlock_repeated_backup => "Multi-share backup", + Self::recovery__unlock_repeated_backup => "Create additional backup?", + Self::recovery__unlock_repeated_backup_verb => "Create backup", + Self::homescreen__set_default => "Change wallpaper to default image?", + Self::reset__words_may_repeat => "Words may repeat.", + Self::reset__repeat_for_all_shares => "Repeat for all shares.", + Self::homescreen__settings_subtitle => "Settings", + Self::homescreen__settings_title => "Homescreen", + Self::reset__the_word_is_repeated => "The word is repeated", + Self::tutorial__title_lets_begin => "Let's begin", + Self::tutorial__did_you_know => "Did you know?", + Self::tutorial__first_wallet => "The Trezor Model One, created in 2013,\nwas the world's first hardware wallet.", + Self::tutorial__restart_tutorial => "Restart tutorial", + Self::tutorial__title_handy_menu => "Handy menu", + Self::tutorial__title_hold => "Hold to confirm important actions", + Self::tutorial__title_well_done => "Well done!", + Self::tutorial__lets_begin => "Learn how to use and navigate this device with ease.", + Self::tutorial__get_started => "Get started!", + Self::instructions__swipe_horizontally => "Swipe horizontally", + Self::setting__adjust => "Adjust", + Self::setting__apply => "Apply", + Self::brightness__changed_title => "Display brightness changed", + Self::brightness__change_title => "Change display brightness", + Self::words__title_done => "Done", + Self::reset__slip39_checklist_more_info_threshold => "The threshold sets the minumum number of shares needed to recover your wallet.", + Self::reset__slip39_checklist_more_info_threshold_example_template => "If you set {0} out of {1} shares, you'll need {2} backup shares to recover your wallet.", + Self::passphrase__continue_with_empty_passphrase => "Continue with empty passphrase?", + #[cfg(feature = "universal_fw")] + Self::fido__more_credentials => "More credentials", + #[cfg(feature = "universal_fw")] + Self::fido__select_intro => "Select the credential that you would like to use for authentication.", + #[cfg(feature = "universal_fw")] + Self::fido__title_for_authentication => "for authentication", + #[cfg(feature = "universal_fw")] + Self::fido__title_select_credential => "Select credential", + Self::instructions__swipe_down => "Swipe down", + #[cfg(feature = "universal_fw")] + Self::fido__title_credential_details => "Credential details", } } @@ -2489,7 +2748,7 @@ impl TranslatedString { Qstr::MP_QSTR_address__title_cosigner => Some(Self::address__title_cosigner), Qstr::MP_QSTR_address__title_receive_address => Some(Self::address__title_receive_address), Qstr::MP_QSTR_address__title_yours => Some(Self::address__title_yours), - Qstr::MP_QSTR_address_details__derivation_path => Some(Self::address_details__derivation_path), + Qstr::MP_QSTR_address_details__derivation_path_colon => Some(Self::address_details__derivation_path_colon), Qstr::MP_QSTR_address_details__title_receive_address => Some(Self::address_details__title_receive_address), Qstr::MP_QSTR_address_details__title_receiving_to => Some(Self::address_details__title_receiving_to), Qstr::MP_QSTR_authenticate__confirm_template => Some(Self::authenticate__confirm_template), @@ -2820,7 +3079,7 @@ impl TranslatedString { Qstr::MP_QSTR_coinjoin__title_do_not_disconnect => Some(Self::coinjoin__title_do_not_disconnect), Qstr::MP_QSTR_coinjoin__title_progress => Some(Self::coinjoin__title_progress), Qstr::MP_QSTR_coinjoin__waiting_for_others => Some(Self::coinjoin__waiting_for_others), - Qstr::MP_QSTR_confirm_total__fee_rate => Some(Self::confirm_total__fee_rate), + Qstr::MP_QSTR_confirm_total__fee_rate_colon => Some(Self::confirm_total__fee_rate_colon), Qstr::MP_QSTR_confirm_total__sending_from_account => Some(Self::confirm_total__sending_from_account), Qstr::MP_QSTR_confirm_total__title_fee => Some(Self::confirm_total__title_fee), Qstr::MP_QSTR_confirm_total__title_sending_from => Some(Self::confirm_total__title_sending_from), @@ -2889,8 +3148,7 @@ impl TranslatedString { Qstr::MP_QSTR_eos__sell_ram => Some(Self::eos__sell_ram), #[cfg(feature = "universal_fw")] Qstr::MP_QSTR_eos__sender => Some(Self::eos__sender), - #[cfg(feature = "universal_fw")] - Qstr::MP_QSTR_eos__sign_transaction => Some(Self::eos__sign_transaction), + Qstr::MP_QSTR_send__sign_transaction => Some(Self::send__sign_transaction), #[cfg(feature = "universal_fw")] Qstr::MP_QSTR_eos__threshold => Some(Self::eos__threshold), #[cfg(feature = "universal_fw")] @@ -3186,10 +3444,10 @@ impl TranslatedString { Qstr::MP_QSTR_nem__unencrypted => Some(Self::nem__unencrypted), #[cfg(feature = "universal_fw")] Qstr::MP_QSTR_nem__unknown_mosaic => Some(Self::nem__unknown_mosaic), - Qstr::MP_QSTR_passphrase__access_hidden_wallet => Some(Self::passphrase__access_hidden_wallet), + Qstr::MP_QSTR_passphrase__access_wallet => Some(Self::passphrase__access_wallet), Qstr::MP_QSTR_passphrase__always_on_device => Some(Self::passphrase__always_on_device), Qstr::MP_QSTR_passphrase__from_host_not_shown => Some(Self::passphrase__from_host_not_shown), - Qstr::MP_QSTR_passphrase__hidden_wallet => Some(Self::passphrase__hidden_wallet), + Qstr::MP_QSTR_passphrase__wallet => Some(Self::passphrase__wallet), Qstr::MP_QSTR_passphrase__hide => Some(Self::passphrase__hide), Qstr::MP_QSTR_passphrase__next_screen_will_show_passphrase => Some(Self::passphrase__next_screen_will_show_passphrase), Qstr::MP_QSTR_passphrase__please_enter => Some(Self::passphrase__please_enter), @@ -3270,7 +3528,7 @@ impl TranslatedString { Qstr::MP_QSTR_recovery__progress_will_be_lost => Some(Self::recovery__progress_will_be_lost), Qstr::MP_QSTR_recovery__select_num_of_words => Some(Self::recovery__select_num_of_words), Qstr::MP_QSTR_recovery__share_already_entered => Some(Self::recovery__share_already_entered), - Qstr::MP_QSTR_recovery__share_from_another_shamir => Some(Self::recovery__share_from_another_shamir), + Qstr::MP_QSTR_recovery__share_from_another_multi_share_backup => Some(Self::recovery__share_from_another_multi_share_backup), Qstr::MP_QSTR_recovery__share_num_template => Some(Self::recovery__share_num_template), Qstr::MP_QSTR_recovery__title => Some(Self::recovery__title), Qstr::MP_QSTR_recovery__title_cancel_dry_run => Some(Self::recovery__title_cancel_dry_run), @@ -3315,7 +3573,7 @@ impl TranslatedString { Qstr::MP_QSTR_reset__never_make_digital_copy => Some(Self::reset__never_make_digital_copy), Qstr::MP_QSTR_reset__num_of_share_holders_template => Some(Self::reset__num_of_share_holders_template), Qstr::MP_QSTR_reset__num_of_shares_advanced_info_template => Some(Self::reset__num_of_shares_advanced_info_template), - Qstr::MP_QSTR_reset__num_of_shares_basic_info => Some(Self::reset__num_of_shares_basic_info), + Qstr::MP_QSTR_reset__num_of_shares_basic_info_template => Some(Self::reset__num_of_shares_basic_info_template), Qstr::MP_QSTR_reset__num_shares_for_group_template => Some(Self::reset__num_shares_for_group_template), Qstr::MP_QSTR_reset__number_of_shares_info => Some(Self::reset__number_of_shares_info), Qstr::MP_QSTR_reset__one_share => Some(Self::reset__one_share), @@ -3409,7 +3667,7 @@ impl TranslatedString { Qstr::MP_QSTR_send__title_sending_amount => Some(Self::send__title_sending_amount), Qstr::MP_QSTR_send__title_sending_to => Some(Self::send__title_sending_to), Qstr::MP_QSTR_send__to_the_total_amount => Some(Self::send__to_the_total_amount), - Qstr::MP_QSTR_send__total_amount => Some(Self::send__total_amount), + Qstr::MP_QSTR_send__total_amount_colon => Some(Self::send__total_amount_colon), Qstr::MP_QSTR_send__transaction_id => Some(Self::send__transaction_id), Qstr::MP_QSTR_send__you_are_contributing => Some(Self::send__you_are_contributing), Qstr::MP_QSTR_share_words__words_in_order => Some(Self::share_words__words_in_order), @@ -3706,8 +3964,138 @@ impl TranslatedString { Qstr::MP_QSTR_storage_msg__starting => Some(Self::storage_msg__starting), Qstr::MP_QSTR_storage_msg__verifying_pin => Some(Self::storage_msg__verifying_pin), Qstr::MP_QSTR_storage_msg__wrong_pin => Some(Self::storage_msg__wrong_pin), - Qstr::MP_QSTR_reset__create_x_of_y_shamir_backup_template => Some(Self::reset__create_x_of_y_shamir_backup_template), + Qstr::MP_QSTR_reset__create_x_of_y_multi_share_backup_template => Some(Self::reset__create_x_of_y_multi_share_backup_template), Qstr::MP_QSTR_reset__title_shamir_backup => Some(Self::reset__title_shamir_backup), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__always_abstain => Some(Self::cardano__always_abstain), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__always_no_confidence => Some(Self::cardano__always_no_confidence), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__delegating_to_key_hash => Some(Self::cardano__delegating_to_key_hash), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__delegating_to_script => Some(Self::cardano__delegating_to_script), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__deposit => Some(Self::cardano__deposit), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_cardano__vote_delegation => Some(Self::cardano__vote_delegation), + Qstr::MP_QSTR_instructions__swipe_up => Some(Self::instructions__swipe_up), + Qstr::MP_QSTR_instructions__tap_to_confirm => Some(Self::instructions__tap_to_confirm), + Qstr::MP_QSTR_instructions__hold_to_confirm => Some(Self::instructions__hold_to_confirm), + Qstr::MP_QSTR_words__important => Some(Self::words__important), + Qstr::MP_QSTR_reset__words_written_down_template => Some(Self::reset__words_written_down_template), + Qstr::MP_QSTR_backup__create_backup_to_prevent_loss => Some(Self::backup__create_backup_to_prevent_loss), + Qstr::MP_QSTR_reset__check_backup_instructions => Some(Self::reset__check_backup_instructions), + Qstr::MP_QSTR_words__instructions => Some(Self::words__instructions), + Qstr::MP_QSTR_words__not_recommended => Some(Self::words__not_recommended), + Qstr::MP_QSTR_address_details__account_info => Some(Self::address_details__account_info), + Qstr::MP_QSTR_address__cancel_contact_support => Some(Self::address__cancel_contact_support), + Qstr::MP_QSTR_address__cancel_receive => Some(Self::address__cancel_receive), + Qstr::MP_QSTR_address__qr_code => Some(Self::address__qr_code), + Qstr::MP_QSTR_address_details__derivation_path => Some(Self::address_details__derivation_path), + Qstr::MP_QSTR_instructions__continue_in_app => Some(Self::instructions__continue_in_app), + Qstr::MP_QSTR_words__cancel_and_exit => Some(Self::words__cancel_and_exit), + Qstr::MP_QSTR_address__confirmed => Some(Self::address__confirmed), + Qstr::MP_QSTR_pin__cancel_description => Some(Self::pin__cancel_description), + Qstr::MP_QSTR_pin__cancel_info => Some(Self::pin__cancel_info), + Qstr::MP_QSTR_pin__cancel_setup => Some(Self::pin__cancel_setup), + Qstr::MP_QSTR_send__cancel_sign => Some(Self::send__cancel_sign), + Qstr::MP_QSTR_send__send_from => Some(Self::send__send_from), + Qstr::MP_QSTR_instructions__hold_to_sign => Some(Self::instructions__hold_to_sign), + Qstr::MP_QSTR_confirm_total__fee_rate => Some(Self::confirm_total__fee_rate), + Qstr::MP_QSTR_send__incl_transaction_fee => Some(Self::send__incl_transaction_fee), + Qstr::MP_QSTR_send__total_amount => Some(Self::send__total_amount), + Qstr::MP_QSTR_auto_lock__turned_on => Some(Self::auto_lock__turned_on), + Qstr::MP_QSTR_backup__info_multi_share_backup => Some(Self::backup__info_multi_share_backup), + Qstr::MP_QSTR_backup__info_single_share_backup => Some(Self::backup__info_single_share_backup), + Qstr::MP_QSTR_backup__title_backup_completed => Some(Self::backup__title_backup_completed), + Qstr::MP_QSTR_backup__title_create_wallet_backup => Some(Self::backup__title_create_wallet_backup), + Qstr::MP_QSTR_haptic_feedback__disable => Some(Self::haptic_feedback__disable), + Qstr::MP_QSTR_haptic_feedback__enable => Some(Self::haptic_feedback__enable), + Qstr::MP_QSTR_haptic_feedback__subtitle => Some(Self::haptic_feedback__subtitle), + Qstr::MP_QSTR_haptic_feedback__title => Some(Self::haptic_feedback__title), + Qstr::MP_QSTR_instructions__continue_holding => Some(Self::instructions__continue_holding), + Qstr::MP_QSTR_instructions__enter_next_share => Some(Self::instructions__enter_next_share), + Qstr::MP_QSTR_instructions__hold_to_continue => Some(Self::instructions__hold_to_continue), + Qstr::MP_QSTR_instructions__hold_to_exit_tutorial => Some(Self::instructions__hold_to_exit_tutorial), + Qstr::MP_QSTR_instructions__hold_to_finish_tutorial => Some(Self::instructions__hold_to_finish_tutorial), + Qstr::MP_QSTR_instructions__learn_more => Some(Self::instructions__learn_more), + Qstr::MP_QSTR_instructions__shares_continue_with_x_template => Some(Self::instructions__shares_continue_with_x_template), + Qstr::MP_QSTR_instructions__shares_start_with_1 => Some(Self::instructions__shares_start_with_1), + Qstr::MP_QSTR_instructions__tap_to_start => Some(Self::instructions__tap_to_start), + Qstr::MP_QSTR_passphrase__title_passphrase => Some(Self::passphrase__title_passphrase), + Qstr::MP_QSTR_recovery__dry_run_backup_not_on_this_device => Some(Self::recovery__dry_run_backup_not_on_this_device), + Qstr::MP_QSTR_recovery__dry_run_invalid_backup_entered => Some(Self::recovery__dry_run_invalid_backup_entered), + Qstr::MP_QSTR_recovery__dry_run_slip39_valid_all_shares => Some(Self::recovery__dry_run_slip39_valid_all_shares), + Qstr::MP_QSTR_recovery__dry_run_slip39_valid_share => Some(Self::recovery__dry_run_slip39_valid_share), + Qstr::MP_QSTR_recovery__dry_run_verify_remaining_shares => Some(Self::recovery__dry_run_verify_remaining_shares), + Qstr::MP_QSTR_recovery__enter_each_word => Some(Self::recovery__enter_each_word), + Qstr::MP_QSTR_recovery__info_about_disconnect => Some(Self::recovery__info_about_disconnect), + Qstr::MP_QSTR_recovery__share_does_not_match => Some(Self::recovery__share_does_not_match), + Qstr::MP_QSTR_reset__cancel_create_wallet => Some(Self::reset__cancel_create_wallet), + Qstr::MP_QSTR_reset__incorrect_word_selected => Some(Self::reset__incorrect_word_selected), + Qstr::MP_QSTR_reset__more_at => Some(Self::reset__more_at), + Qstr::MP_QSTR_reset__num_of_shares_how_many => Some(Self::reset__num_of_shares_how_many), + Qstr::MP_QSTR_reset__num_of_shares_long_info_template => Some(Self::reset__num_of_shares_long_info_template), + Qstr::MP_QSTR_reset__select_threshold => Some(Self::reset__select_threshold), + Qstr::MP_QSTR_reset__share_completed_template => Some(Self::reset__share_completed_template), + Qstr::MP_QSTR_reset__slip39_checklist_num_shares_x_template => Some(Self::reset__slip39_checklist_num_shares_x_template), + Qstr::MP_QSTR_reset__slip39_checklist_threshold_x_template => Some(Self::reset__slip39_checklist_threshold_x_template), + Qstr::MP_QSTR_send__transaction_signed => Some(Self::send__transaction_signed), + Qstr::MP_QSTR_tutorial__continue => Some(Self::tutorial__continue), + Qstr::MP_QSTR_tutorial__exit => Some(Self::tutorial__exit), + Qstr::MP_QSTR_tutorial__first_transaction_finish => Some(Self::tutorial__first_transaction_finish), + Qstr::MP_QSTR_tutorial__first_transaction_intro => Some(Self::tutorial__first_transaction_intro), + Qstr::MP_QSTR_tutorial__menu => Some(Self::tutorial__menu), + Qstr::MP_QSTR_tutorial__one_more_step => Some(Self::tutorial__one_more_step), + Qstr::MP_QSTR_tutorial__ready_to_use_safe5 => Some(Self::tutorial__ready_to_use_safe5), + Qstr::MP_QSTR_tutorial__subtitle_safe5 => Some(Self::tutorial__subtitle_safe5), + Qstr::MP_QSTR_tutorial__swipe_up_and_down => Some(Self::tutorial__swipe_up_and_down), + Qstr::MP_QSTR_tutorial__title_easy_navigation => Some(Self::tutorial__title_easy_navigation), + Qstr::MP_QSTR_tutorial__welcome_safe5 => Some(Self::tutorial__welcome_safe5), + Qstr::MP_QSTR_words__good_to_know => Some(Self::words__good_to_know), + Qstr::MP_QSTR_words__operation_cancelled => Some(Self::words__operation_cancelled), + Qstr::MP_QSTR_words__settings => Some(Self::words__settings), + Qstr::MP_QSTR_words__try_again => Some(Self::words__try_again), + Qstr::MP_QSTR_reset__slip39_checklist_num_groups_x_template => Some(Self::reset__slip39_checklist_num_groups_x_template), + Qstr::MP_QSTR_brightness__title => Some(Self::brightness__title), + Qstr::MP_QSTR_recovery__title_unlock_repeated_backup => Some(Self::recovery__title_unlock_repeated_backup), + Qstr::MP_QSTR_recovery__unlock_repeated_backup => Some(Self::recovery__unlock_repeated_backup), + Qstr::MP_QSTR_recovery__unlock_repeated_backup_verb => Some(Self::recovery__unlock_repeated_backup_verb), + Qstr::MP_QSTR_homescreen__set_default => Some(Self::homescreen__set_default), + Qstr::MP_QSTR_reset__words_may_repeat => Some(Self::reset__words_may_repeat), + Qstr::MP_QSTR_reset__repeat_for_all_shares => Some(Self::reset__repeat_for_all_shares), + Qstr::MP_QSTR_homescreen__settings_subtitle => Some(Self::homescreen__settings_subtitle), + Qstr::MP_QSTR_homescreen__settings_title => Some(Self::homescreen__settings_title), + Qstr::MP_QSTR_reset__the_word_is_repeated => Some(Self::reset__the_word_is_repeated), + Qstr::MP_QSTR_tutorial__title_lets_begin => Some(Self::tutorial__title_lets_begin), + Qstr::MP_QSTR_tutorial__did_you_know => Some(Self::tutorial__did_you_know), + Qstr::MP_QSTR_tutorial__first_wallet => Some(Self::tutorial__first_wallet), + Qstr::MP_QSTR_tutorial__restart_tutorial => Some(Self::tutorial__restart_tutorial), + Qstr::MP_QSTR_tutorial__title_handy_menu => Some(Self::tutorial__title_handy_menu), + Qstr::MP_QSTR_tutorial__title_hold => Some(Self::tutorial__title_hold), + Qstr::MP_QSTR_tutorial__title_well_done => Some(Self::tutorial__title_well_done), + Qstr::MP_QSTR_tutorial__lets_begin => Some(Self::tutorial__lets_begin), + Qstr::MP_QSTR_tutorial__get_started => Some(Self::tutorial__get_started), + Qstr::MP_QSTR_instructions__swipe_horizontally => Some(Self::instructions__swipe_horizontally), + Qstr::MP_QSTR_setting__adjust => Some(Self::setting__adjust), + Qstr::MP_QSTR_setting__apply => Some(Self::setting__apply), + Qstr::MP_QSTR_brightness__changed_title => Some(Self::brightness__changed_title), + Qstr::MP_QSTR_brightness__change_title => Some(Self::brightness__change_title), + Qstr::MP_QSTR_words__title_done => Some(Self::words__title_done), + Qstr::MP_QSTR_reset__slip39_checklist_more_info_threshold => Some(Self::reset__slip39_checklist_more_info_threshold), + Qstr::MP_QSTR_reset__slip39_checklist_more_info_threshold_example_template => Some(Self::reset__slip39_checklist_more_info_threshold_example_template), + Qstr::MP_QSTR_passphrase__continue_with_empty_passphrase => Some(Self::passphrase__continue_with_empty_passphrase), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_fido__more_credentials => Some(Self::fido__more_credentials), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_fido__select_intro => Some(Self::fido__select_intro), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_fido__title_for_authentication => Some(Self::fido__title_for_authentication), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_fido__title_select_credential => Some(Self::fido__title_select_credential), + Qstr::MP_QSTR_instructions__swipe_down => Some(Self::instructions__swipe_down), + #[cfg(feature = "universal_fw")] + Qstr::MP_QSTR_fido__title_credential_details => Some(Self::fido__title_credential_details), _ => None, } } diff --git a/core/embed/rust/src/translations/generated/translated_string.rs.mako b/core/embed/rust/src/translations/generated/translated_string.rs.mako index 74acf67577..9ecc94fbcf 100644 --- a/core/embed/rust/src/translations/generated/translated_string.rs.mako +++ b/core/embed/rust/src/translations/generated/translated_string.rs.mako @@ -5,6 +5,7 @@ #![cfg_attr(rustfmt, rustfmt_skip)] <% import json +import re ALTCOIN_PREFIXES = ( "binance", @@ -35,7 +36,8 @@ en_data = json.loads(en_file.read_text())["translations"] #[cfg(feature = "micropython")] use crate::micropython::qstr::Qstr; -#[derive(Debug, Copy, Clone, FromPrimitive, PartialEq, Eq)] +#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] #[repr(u16)] #[allow(non_camel_case_types)] pub enum TranslatedString { @@ -54,7 +56,7 @@ impl TranslatedString { %if any(name.startswith(prefix + "__") for prefix in ALTCOIN_PREFIXES): #[cfg(feature = "universal_fw")] %endif - Self::${name} => ${json.dumps(en_data.get(name, '""'))}, + Self::${name} => ${re.sub(r'\\u([0-9a-f]{4})', r'\\u{\g<1>}', json.dumps(en_data.get(name, '""')))}, % endfor } } diff --git a/core/embed/rust/src/translations/mod.rs b/core/embed/rust/src/translations/mod.rs index ee527a67b4..3d19ef4b48 100644 --- a/core/embed/rust/src/translations/mod.rs +++ b/core/embed/rust/src/translations/mod.rs @@ -6,7 +6,6 @@ mod obj; mod public_keys; mod translated_string; -pub use blob::MAX_HEADER_LEN; pub use translated_string::TranslatedString as TR; pub const DEFAULT_LANGUAGE: &str = "en-US"; diff --git a/core/embed/rust/src/translations/obj.rs b/core/embed/rust/src/translations/obj.rs index 7ba6fb4db0..9b341abdc7 100644 --- a/core/embed/rust/src/translations/obj.rs +++ b/core/embed/rust/src/translations/obj.rs @@ -4,6 +4,9 @@ use crate::{ micropython::{ buffer::{get_buffer, StrBuffer}, ffi, + macros::{ + attr_tuple, obj_dict, obj_fn_0, obj_fn_1, obj_fn_2, obj_map, obj_module, obj_type, + }, map::Map, module::Module, obj::Obj, diff --git a/core/embed/rust/src/trezorhal/bitblt.rs b/core/embed/rust/src/trezorhal/bitblt.rs new file mode 100644 index 0000000000..dea82a0ea6 --- /dev/null +++ b/core/embed/rust/src/trezorhal/bitblt.rs @@ -0,0 +1,448 @@ +use super::ffi; + +use crate::ui::{ + display::Color, + geometry::Rect, + shape::{Bitmap, BitmapFormat, BitmapView}, +}; + +/// Waits for the DMA2D peripheral transfer to complete. +pub fn wait_for_transfer() { + // SAFETY: + // `ffi::dma2d_wait()` is always safe to call. + #[cfg(feature = "dma2d")] + unsafe { + ffi::dma2d_wait() + } +} + +impl Default for ffi::gfx_bitblt_t { + fn default() -> Self { + Self { + width: 0, + height: 0, + dst_row: core::ptr::null_mut(), + dst_stride: 0, + dst_x: 0, + dst_y: 0, + src_row: core::ptr::null_mut(), + src_bg: 0, + src_fg: 0, + src_stride: 0, + src_x: 0, + src_y: 0, + src_alpha: 255, + } + } +} + +// This is very private interface (almost completely unsafe) to +// preparing a `gfx_bitblt_t` structure for the bitblt operations. +impl ffi::gfx_bitblt_t { + /// Sets the destination bitmap pointer and stride. + /// + /// # SAFETY + /// 1) Ensure that caller holds mutable reference to the destination bitmap + /// until the `gfx_bitblt_t` is dropped. + unsafe fn with_dst(self, dst: &mut Bitmap) -> Self { + // This ensures that the destination rectangle is + // completely inside the destination bitmap + assert!(dst.width() as u16 >= self.dst_x + self.width); + assert!(dst.height() as u16 >= self.dst_y + self.height); + + Self { + // SAFETY: + // Lines between `dst_y` and`dst_y + height` are inside + // the destination bitmap. See asserts above. + dst_row: unsafe { dst.row_ptr(self.dst_y) }, + dst_stride: dst.stride() as u16, + ..self + } + } + + /// Sets the coordinates of the destination rectangle inside the destination + /// bitmap. + /// + /// # SAFETY + /// 1) Ensure that the rectangle is completely inside the destination + /// bitmap. + /// 2) If the copy or blend operation is used, ensure that the rectangle is + /// completely filled with source bitmap or its part. + unsafe fn with_rect(self, r: Rect) -> Self { + Self { + width: r.width() as u16, + height: r.height() as u16, + dst_x: r.x0 as u16, + dst_y: r.y0 as u16, + ..self + } + } + + /// Sets the source bitmap + /// + /// `x` and `y` specifies offset inside the source bitmap + /// + /// # SAFETY + /// 1) Ensure that `x` and `y` are inside the source bitmap. + /// 2) Source bitmap complete covers destination rectangle. + /// 3) Ensure that caller holds immutable reference to the source bitmap. + /// until the `gfx_bitblt_t` is dropped. + unsafe fn with_src(self, bitmap: &Bitmap, x: i16, y: i16) -> Self { + let bitmap_stride = match bitmap.format() { + BitmapFormat::MONO1P => bitmap.width() as u16, // packed bits + _ => bitmap.stride() as u16, + }; + + Self { + // SAFETY: + // It's safe if `y` is inside the bitmap (see note above) + src_row: unsafe { bitmap.row_ptr(y as u16) }, + src_stride: bitmap_stride, + src_x: x as u16, + src_y: y as u16, + ..self + } + } + + /// Sets foreground color used for rectangle filling or + /// drawing monochrome bitmaps. + fn with_fg(self, fg_color: Color) -> Self { + Self { + src_fg: fg_color.into(), + ..self + } + } + + /// Sets foreground color used for drawing monochrome bitmaps. + fn with_bg(self, bg_color: Color) -> Self { + Self { + src_bg: bg_color.into(), + ..self + } + } + + /// Sets the foreground alpha value used for rectangle filling or + /// bitmap blending. + fn with_alpha(self, alpha: u8) -> Self { + Self { + src_alpha: alpha, + ..self + } + } +} + +/// Rectangle filling operation. +pub struct BitBltFill { + bitblt: ffi::gfx_bitblt_t, +} + +impl BitBltFill { + /// Prepares bitblt **fill** operation + /// + /// - `r` is the rectangle to fill. + /// - `clip` is the clipping rectangle and must be completely inside the + /// destination bitmap. + /// - `color` is the color to fill the rectangle with. + /// - `alpha` is the alpha value to use for blending. + /// + /// The function ensures proper clipping and returns `None` if the fill + /// operation is not needed. + pub fn new(r: Rect, clip: Rect, color: Color, alpha: u8) -> Option { + let r = r.clamp(clip); + if !r.is_empty() { + Some(Self { + // SAFETY: + // The only unsafe operation is `.with_rect()`, which is safe + // as long as the rectangle is completely inside the destination bitmap. + // We will set the destination bitmap later, so at the moment the + // rectangle cannot be out of bounds. + bitblt: unsafe { + ffi::gfx_bitblt_t::default() + .with_rect(r) + .with_fg(color) + .with_alpha(alpha) + }, + }) + } else { + None + } + } + + /// Fills a rectangle in the destination bitmap with the specified color. + /// + /// Destination bitmap must be in RGB565 format + pub fn rgb565_fill(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGB565); + // SAFETY: + // - The destination bitmap is in the correct format. + // - The destination rectangle is completely inside the destination bitmap. + unsafe { ffi::gfx_rgb565_fill(&self.bitblt.with_dst(dst)) }; + dst.mark_dma_pending(); + } + + /// Fills a rectangle in the destination bitmap with the specified color. + /// + /// The destination bitmap is in the RGBA8888 format. + pub fn rgba8888_fill(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGBA8888); + // SAFETY: + // - The destination bitmap is in the correct format. + // - The destination rectangle is completely inside the destination bitmap. + unsafe { ffi::gfx_rgba8888_fill(&self.bitblt.with_dst(dst)) }; + dst.mark_dma_pending(); + } + + /// Fills a rectangle in the destination bitmap with the specified color. + /// + /// The destination bitmap is in the MONO8 format. + pub fn mono8_fill(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::MONO8); + // SAFETY: + // - The destination bitmap is in the correct format. + // - The destination rectangle is completely inside the destination bitmap. + unsafe { ffi::gfx_mono8_fill(&self.bitblt.with_dst(dst)) }; + dst.mark_dma_pending(); + } + + /// Fills a rectangle on the display with the specified color. + #[cfg(feature = "new_rendering")] + pub fn display_fill(&self) { + assert!(self.bitblt.dst_x + self.bitblt.width <= ffi::DISPLAY_RESX as u16); + assert!(self.bitblt.dst_y + self.bitblt.height <= ffi::DISPLAY_RESY as u16); + // SAFETY: + // - The destination rectangle is completely inside the display. + unsafe { ffi::display_fill(&self.bitblt) }; + } +} + +/// Rectangle copying or blending operation. +pub struct BitBltCopy<'a> { + bitblt: ffi::gfx_bitblt_t, + src: &'a BitmapView<'a>, +} + +impl<'a> BitBltCopy<'a> { + /// Prepares `BitBltCopy` structure for copying or blending a part of the + /// source bitmap to the destination bitmap or display. + /// + /// - `r` is the rectangle in the destination bitmap. + /// - `clip` is the clipping rectangle and must be completely inside the + /// destination bitmap. + /// - `src` represents the source bitmap. + /// + /// The function ensures proper clipping and returns `None` if the copy + /// operation is not needed. + pub fn new(r: Rect, clip: Rect, src: &'a BitmapView) -> Option { + let mut offset = src.offset; + let mut r_dst = r; + + // Normalize negative x & y-offset of the bitmap + if offset.x < 0 { + r_dst.x0 -= offset.x; + offset.x = 0; + } + + if offset.y < 0 { + r_dst.y0 -= offset.y; + offset.y = 0; + } + + // Clip with the canvas viewport + let mut r = r_dst.clamp(clip); + + // Clip with the bitmap top-left + if r.x0 > r_dst.x0 { + offset.x += r.x0 - r_dst.x0; + } + + if r.y0 > r_dst.y0 { + offset.y += r.y0 - r_dst.y0; + } + + // Clip with the bitmap size + r.x1 = r.x1.min(r.x0 + src.size().x - offset.x); + r.y1 = r.y1.min(r.y0 + src.size().y - offset.y); + + if !r.is_empty() { + Some(Self { + // SAFETY: + // The only unsafe operations are `.with_rect()` and `.with_src()`: + // - There is currently no set destination so the destination rectangle can't be out + // of bounds + // - The `x`, `y` offsets are within the source bitmap, as ensured by the preceding + // code. + // - The source bitmap completely covers the destination rectangle, which is also + // ensured by the preceding code. + // - We hold a immutable reference to the source bitmap in the `BitBltCopy` + // structure. + bitblt: unsafe { + ffi::gfx_bitblt_t::default() + .with_rect(r) + .with_src(src.bitmap, offset.x, offset.y) + .with_bg(src.bg_color) + .with_fg(src.fg_color) + .with_alpha(src.alpha) + }, + src, + }) + } else { + None + } + } + + /// Copies a part of the source bitmap to the destination bitmap in RGB565 + /// format. + pub fn rgb565_copy(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGB565); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO4 => ffi::gfx_rgb565_copy_mono4(&bitblt), + BitmapFormat::RGB565 => ffi::gfx_rgb565_copy_rgb565(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Blends a part of the source bitmap with the destination bitmap in RGB565 + /// format. + pub fn rgb565_blend(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGB565); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO4 => ffi::gfx_rgb565_blend_mono4(&bitblt), + BitmapFormat::MONO8 => ffi::gfx_rgb565_blend_mono8(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Copies a part of the source bitmap to the destination bitmap in RGBA8888 + /// format. + pub fn rgba8888_copy(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGBA8888); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO4 => ffi::gfx_rgba8888_copy_mono4(&bitblt), + BitmapFormat::RGB565 => ffi::gfx_rgba8888_copy_rgb565(&bitblt), + BitmapFormat::RGBA8888 => ffi::gfx_rgba8888_copy_rgba8888(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Blends a part of the source bitmap with the destination bitmap in + /// RGBA8888 format. + pub fn rgba8888_blend(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::RGBA8888); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO4 => ffi::gfx_rgba8888_blend_mono4(&bitblt), + BitmapFormat::MONO8 => ffi::gfx_rgba8888_blend_mono8(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Copies a part of the source bitmap to the destination bitmap in MONO8 + /// format. + pub fn mono8_copy(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::MONO8); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO1P => ffi::gfx_mono8_copy_mono1p(&bitblt), + BitmapFormat::MONO4 => ffi::gfx_mono8_copy_mono4(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Blends a part of the source bitmap with the destination bitmap in MONO8 + /// format. + pub fn mono8_blend(&self, dst: &mut Bitmap) { + assert!(dst.format() == BitmapFormat::MONO8); + + // SAFETY: + // - The destination and source bitmaps are in the correct formats. + // - Source and destination coordinates are properly clipped + // - The DMA pending flag is set for both bitmaps after operations. + unsafe { + let bitblt = self.bitblt.with_dst(dst); + match self.src.format() { + BitmapFormat::MONO1P => ffi::gfx_mono8_blend_mono1p(&bitblt), + BitmapFormat::MONO4 => ffi::gfx_mono8_blend_mono4(&bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + dst.mark_dma_pending(); + } + + /// Copies a part of the source bitmap to the display. + /// + /// - The source bitmap uses the RGB565 format. + #[cfg(feature = "new_rendering")] + pub fn display_copy(&self) { + assert!(self.bitblt.dst_x + self.bitblt.width <= ffi::DISPLAY_RESX as u16); + assert!(self.bitblt.dst_y + self.bitblt.height <= ffi::DISPLAY_RESY as u16); + + // SAFETY: + // - The source bitmap is in the correct formats. + // - Source and destination coordinates are properly clipped + // - The destination rectangle is completely inside the display. + // - The DMA pending flag is set for src bitmap after operations. + unsafe { + match self.src.format() { + BitmapFormat::RGB565 => ffi::display_copy_rgb565(&self.bitblt), + _ => unimplemented!(), + } + } + + self.src.bitmap.mark_dma_pending(); + } +} diff --git a/core/embed/rust/src/trezorhal/display.rs b/core/embed/rust/src/trezorhal/display.rs index 95a17350be..b2713f695a 100644 --- a/core/embed/rust/src/trezorhal/display.rs +++ b/core/embed/rust/src/trezorhal/display.rs @@ -13,11 +13,11 @@ pub use ffi::{ #[cfg(all(feature = "framebuffer", not(feature = "framebuffer32bit")))] #[derive(Copy, Clone)] -pub struct FrameBuffer(*mut u16); +pub struct FrameBuffer(pub *mut u16); #[cfg(all(feature = "framebuffer", feature = "framebuffer32bit"))] #[derive(Copy, Clone)] -pub struct FrameBuffer(*mut u32); +pub struct FrameBuffer(pub *mut u32); pub fn backlight(val: i32) -> i32 { unsafe { ffi::display_backlight(val) } @@ -98,7 +98,9 @@ pub fn get_fb_addr() -> FrameBuffer { #[inline(always)] #[cfg(all(not(feature = "framebuffer"), feature = "disp_i8080_8bit_dw"))] +#[allow(unused_variables)] pub fn pixeldata(c: u16) { + #[cfg(not(feature = "new_rendering"))] unsafe { ffi::DISPLAY_DATA_ADDRESS.write_volatile((c & 0xff) as u8); ffi::DISPLAY_DATA_ADDRESS.write_volatile((c >> 8) as u8); @@ -178,3 +180,17 @@ pub fn clear() { ffi::display_clear(); } } + +#[cfg(feature = "xframebuffer")] +pub fn get_frame_buffer() -> (&'static mut [u8], usize) { + let fb_info = unsafe { ffi::display_get_frame_buffer() }; + + let fb = unsafe { + core::slice::from_raw_parts_mut( + fb_info.ptr as *mut u8, + DISPLAY_RESY as usize * fb_info.stride, + ) + }; + + (fb, fb_info.stride) +} diff --git a/core/embed/rust/src/trezorhal/fatal_error.rs b/core/embed/rust/src/trezorhal/fatal_error.rs index de0e1188fb..20c9692bbb 100644 --- a/core/embed/rust/src/trezorhal/fatal_error.rs +++ b/core/embed/rust/src/trezorhal/fatal_error.rs @@ -5,92 +5,68 @@ mod ffi { } } -use crate::ui::ui_features::{ModelUI, UIFeaturesCommon}; +use crate::ui::{ + shape, + ui_features::{ModelUI, UIFeaturesCommon}, +}; fn shutdown() -> ! { unsafe { ffi::trezor_shutdown() } } -#[cfg(feature = "bootloader")] -pub fn __fatal_error(_expr: &str, _msg: &str, _file: &str, _line: u32, _func: &str) -> ! { - ModelUI::screen_fatal_error("BL.rs", "BL.rs", "PLEASE VISIT\nTREZOR.IO/RSOD"); +/// Shows an error message and shuts down the device. +pub fn error_shutdown(title: &str, msg: &str, footer: &str) -> ! { + // SAFETY: + // This is the only situation we are allowed use this function + // to allow nested calls to `run_with_bumps`/`render_on_display`, + // because after the error message is displayed, the application will + // shut down. + unsafe { shape::unlock_bumps_on_failure() }; + + ModelUI::screen_fatal_error(title, msg, footer); ModelUI::backlight_on(); shutdown() } -#[cfg(not(feature = "bootloader"))] -pub fn __fatal_error(_expr: &str, msg: &str, _file: &str, _line: u32, _func: &str) -> ! { - ModelUI::screen_fatal_error("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); - ModelUI::backlight_on(); - shutdown() +/// Shows an error message on the screen and shuts down the device. +/// In debug mode, also prints the error message to the console. +#[inline(never)] // saves few kilobytes of flash +pub fn __fatal_error(msg: &str, _file: &str, _line: u32) -> ! { + #[cfg(feature = "debug")] + { + dbg_println!("=== FATAL ERROR"); + + if _line != 0 { + dbg_println!("Location: {}:{}", _file, _line); + } + if !msg.is_empty() { + dbg_println!("Message: {}", msg); + } + + dbg_println!("==="); + } + + error_shutdown("INTERNAL_ERROR", msg, "PLEASE VISIT\nTREZOR.IO/RSOD"); } pub trait UnwrapOrFatalError { - fn unwrap_or_fatal_error(self, expr: &str, msg: &str, file: &str, line: u32, func: &str) -> T; + fn unwrap_or_fatal_error(self, msg: &str, file: &str, line: u32) -> T; } impl UnwrapOrFatalError for Option { - fn unwrap_or_fatal_error(self, expr: &str, msg: &str, file: &str, line: u32, func: &str) -> T { + fn unwrap_or_fatal_error(self, msg: &str, file: &str, line: u32) -> T { match self { Some(x) => x, - None => __fatal_error(expr, msg, file, line, func), + None => __fatal_error(msg, file, line), } } } impl UnwrapOrFatalError for Result { - fn unwrap_or_fatal_error(self, expr: &str, msg: &str, file: &str, line: u32, func: &str) -> T { + fn unwrap_or_fatal_error(self, msg: &str, file: &str, line: u32) -> T { match self { Ok(x) => x, - Err(_) => __fatal_error(expr, msg, file, line, func), + Err(_) => __fatal_error(msg, file, line), } } } - -macro_rules! function_name { - () => {{ - #[cfg(not(feature = "bootloader"))] - { - fn f() {} - fn type_name_of(_: T) -> &'static str { - core::any::type_name::() - } - let name = type_name_of(f); - name.get(..name.len() - 3).unwrap_or("") - } - #[cfg(feature = "bootloader")] - { - "" - } - }}; -} - -macro_rules! unwrap { - ($e:expr, $msg:expr) => {{ - use crate::trezorhal::fatal_error::UnwrapOrFatalError; - $e.unwrap_or_fatal_error(stringify!($e), $msg, file!(), line!(), function_name!()) - }}; - ($expr:expr) => { - unwrap!($expr, "unwrap failed") - }; -} - -macro_rules! ensure { - ($what:expr, $error:expr) => { - if !($what) { - fatal_error!(stringify!($what), $error); - } - }; -} - -macro_rules! fatal_error { - ($expr:expr, $msg:expr) => {{ - crate::trezorhal::fatal_error::__fatal_error( - stringify!($expr), - $msg, - file!(), - line!(), - function_name!(), - ); - }}; -} diff --git a/core/embed/rust/src/trezorhal/haptic.rs b/core/embed/rust/src/trezorhal/haptic.rs index d76474c2b3..a1f75700e3 100644 --- a/core/embed/rust/src/trezorhal/haptic.rs +++ b/core/embed/rust/src/trezorhal/haptic.rs @@ -11,3 +11,9 @@ pub fn play(effect: HapticEffect) { ffi::haptic_play(effect as _); } } + +pub fn play_custom(amplitude_pct: i8, duration_ms: u16) { + unsafe { + ffi::haptic_play_custom(amplitude_pct, duration_ms); + } +} diff --git a/core/embed/rust/src/trezorhal/io.rs b/core/embed/rust/src/trezorhal/io.rs index 7f9af446fb..6ece57df9f 100644 --- a/core/embed/rust/src/trezorhal/io.rs +++ b/core/embed/rust/src/trezorhal/io.rs @@ -1,8 +1,8 @@ use super::ffi; #[cfg(feature = "touch")] -pub fn io_touch_read() -> u32 { - unsafe { ffi::touch_read() } +pub fn io_touch_get_event() -> u32 { + unsafe { ffi::touch_get_event() } } #[cfg(feature = "button")] diff --git a/core/embed/rust/src/trezorhal/mod.rs b/core/embed/rust/src/trezorhal/mod.rs index 39de951510..bab3c62660 100644 --- a/core/embed/rust/src/trezorhal/mod.rs +++ b/core/embed/rust/src/trezorhal/mod.rs @@ -3,12 +3,15 @@ pub mod bip39; #[allow(unused_macros)] pub mod fatal_error; #[cfg(feature = "ui")] +pub mod bitblt; +#[cfg(feature = "ui")] pub mod display; #[cfg(feature = "dma2d")] pub mod dma2d; mod ffi; #[cfg(feature = "haptic")] pub mod haptic; + pub mod io; pub mod model; pub mod random; diff --git a/core/embed/rust/src/trezorhal/slip39.rs b/core/embed/rust/src/trezorhal/slip39.rs index 6d061c8856..cc7e568680 100644 --- a/core/embed/rust/src/trezorhal/slip39.rs +++ b/core/embed/rust/src/trezorhal/slip39.rs @@ -1,5 +1,4 @@ -use core::str; -use cstr_core::CStr; +use core::{ffi::CStr, str}; use super::ffi; @@ -26,6 +25,6 @@ pub fn button_sequence_to_word(prefix: u16) -> Option<&'static str> { } else { // SAFETY: On success, `button_sequence_to_word` should return a 0-terminated // UTF-8 string with static lifetime. - Some(unsafe { str::from_utf8_unchecked(CStr::from_ptr(word).to_bytes()) }) + Some(unsafe { str::from_utf8_unchecked(CStr::from_ptr(word as _).to_bytes()) }) } } diff --git a/core/embed/rust/src/trezorhal/storage.rs b/core/embed/rust/src/trezorhal/storage.rs index 3013a009d4..6bf44a3b71 100644 --- a/core/embed/rust/src/trezorhal/storage.rs +++ b/core/embed/rust/src/trezorhal/storage.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] use super::ffi; -use crate::error::Error; +use crate::error::{value_error, Error}; use core::ptr; use num_traits::FromPrimitive; @@ -80,12 +80,12 @@ pub enum StorageError { impl From for Error { fn from(err: StorageError) -> Self { match err { - StorageError::InvalidData => value_error!("Invalid data for storage"), - StorageError::WriteFailed => value_error!("Storage write failed"), - StorageError::ReadFailed => value_error!("Storage read failed"), - StorageError::DeleteFailed => value_error!("Storage delete failed"), + StorageError::InvalidData => value_error!(c"Invalid data for storage"), + StorageError::WriteFailed => value_error!(c"Storage write failed"), + StorageError::ReadFailed => value_error!(c"Storage read failed"), + StorageError::DeleteFailed => value_error!(c"Storage delete failed"), StorageError::CounterFailed => { - value_error!("Retrieving counter value failed") + value_error!(c"Retrieving counter value failed") } } } diff --git a/core/embed/rust/src/trezorhal/translations.rs b/core/embed/rust/src/trezorhal/translations.rs index 7761087dde..edac8f0543 100644 --- a/core/embed/rust/src/trezorhal/translations.rs +++ b/core/embed/rust/src/trezorhal/translations.rs @@ -7,7 +7,7 @@ pub unsafe fn get_blob<'a>() -> &'a [u8] { let mut len: u32 = 0; let ptr = unsafe { ffi::translations_read(&mut len, 0) }; if ptr.is_null() { - fatal_error!("Translations read failed", ""); + fatal_error!("Translations read failed"); } // SAFETY: The pointer is always valid. unsafe { core::slice::from_raw_parts(ptr, len as usize) } diff --git a/core/embed/rust/src/trezorhal/uzlib.rs b/core/embed/rust/src/trezorhal/uzlib.rs index bfd3246feb..5ff7f7b4a0 100644 --- a/core/embed/rust/src/trezorhal/uzlib.rs +++ b/core/embed/rust/src/trezorhal/uzlib.rs @@ -1,5 +1,6 @@ use super::ffi; -use core::{marker::PhantomData, mem::MaybeUninit, ptr}; +use crate::io::BinaryData; +use core::{cell::RefCell, marker::PhantomData, mem::MaybeUninit, ptr}; pub const UZLIB_WINDOW_SIZE: usize = 1 << 10; pub use ffi::uzlib_uncomp; @@ -19,7 +20,7 @@ impl<'a> UzlibContext<'a> { pub fn new(src: &'a [u8], window: Option<&'a mut [u8; UZLIB_WINDOW_SIZE]>) -> Self { let mut ctx = Self { uncomp: uzlib_uncomp::default(), - src_data: Default::default(), + src_data: PhantomData, }; unsafe { @@ -55,6 +56,158 @@ impl<'a> UzlibContext<'a> { } } } +} + +struct SourceReadContext<'a> { + /// Compressed data + data: BinaryData<'a>, + /// Ofsset in the compressed data + // (points to the next byte to read) + offset: usize, + /// Internal buffer for reading compressed data + buf: [u8; 128], + buf_head: usize, + buf_tail: usize, +} + +impl<'a> SourceReadContext<'a> { + pub fn new(data: BinaryData<'a>, offset: usize) -> Self { + Self { + data, + offset, + buf: [0; 128], + buf_head: 0, + buf_tail: 0, + } + } + + /// Fill the uncomp struct with the appropriate pointers to the source data + pub fn prepare_uncomp(&self, uncomp: &mut ffi::uzlib_uncomp) { + // SAFETY: the offsets are within the buffer bounds. + // - buf_head is either 0 or advanced by uzlib to at most buf_tail (via + // advance()) + // - buf_tail is at most the buffer size (via reader_callback()) + unsafe { + uncomp.source = self.buf.as_ptr().add(self.buf_head); + uncomp.source_limit = self.buf.as_ptr().add(self.buf_tail); + } + } + + /// Advance the internal buffer after a read operation + /// + /// # Safety + /// + /// The operation is only valid on an uncomp struct that has been filled via + /// `prepare_uncomp` and the source pointer has been updated by the uzlib + /// library after a single uncompress operation. + pub unsafe fn advance(&mut self, uncomp: &ffi::uzlib_uncomp) { + unsafe { + // SAFETY: we trust uzlib to move the `source` pointer only up to `source_limit` + self.buf_head = uncomp.source.offset_from(self.buf.as_ptr()) as usize; + } + } + + /// Implement uzlib reader callback. + /// + /// If the uncomp buffer is exhausted, a callback is invoked that should (a) + /// read one byte of data, and optionally (b) update the uncomp buffer + /// with more data. + pub fn reader_callback(&mut self, uncomp: &mut ffi::uzlib_uncomp) -> Option { + // fill the internal buffer first + let bytes_read = self.data.read(self.offset, self.buf.as_mut()); + self.buf_head = 0; + self.buf_tail = bytes_read; + // advance total offset + self.offset += bytes_read; + + if bytes_read > 0 { + // "read" one byte + self.buf_head += 1; + // update the uncomp struct + self.prepare_uncomp(uncomp); + // return the first byte read + Some(self.buf[0]) + } else { + // EOF + None + } + } +} + +pub struct ZlibInflate<'a> { + /// Compressed data reader + data: RefCell>, + /// Uzlib context + uncomp: ffi::uzlib_uncomp, + window: PhantomData<&'a [u8]>, +} + +impl<'a> ZlibInflate<'a> { + /// Creates a new `ZlibInflate` instance. + /// - `data` - compressed data + /// - `offset` - initial offset in the compressed data + /// - `window` - window buffer for decompression + pub fn new( + data: BinaryData<'a>, + offset: usize, + window: &'a mut [u8; UZLIB_WINDOW_SIZE], + ) -> Self { + let mut inflate = Self { + data: RefCell::new(SourceReadContext::new(data, offset)), + uncomp: uzlib_uncomp::default(), + window: PhantomData, + }; + + // SAFETY: + // `window` is a valid mutable slice with the size of UZLIB_WINDOW_SIZE + // it remains valid until the `ZlibInflate` instance is dropped + unsafe { + let window_ptr = window.as_mut_ptr() as _; + let window_size = UZLIB_WINDOW_SIZE as u32; + ffi::uzlib_uncompress_init(&mut inflate.uncomp, window_ptr, window_size); + } + + inflate + } + + /// Reads uncompressed data into the destination buffer. + /// Returns `Ok(true)` if all data was read + pub fn read(&mut self, dest: &mut [u8]) -> Result { + // Fill out source data pointers + self.data.borrow().prepare_uncomp(&mut self.uncomp); + + let res = unsafe { + // Source data callback (used to read more data when source is exhausted) + self.uncomp.source_read_cb = Some(zlib_reader_callback); + // Context for the source data callback + self.uncomp.source_read_cb_context = &self.data as *const _ as *mut cty::c_void; + + // Destination buffer + self.uncomp.dest = dest.as_mut_ptr(); + self.uncomp.dest_limit = self.uncomp.dest.add(dest.len()); + + // SAFETY: + // Even if the `ZlibInflate` instance is moved, the source and context + // pointers are still valid as we set them before calling `uzlib_uncompress` + let res = ffi::uzlib_uncompress(&mut self.uncomp); + + // `uzlib_uncompress` moved self.uncomp.source to the next byte to read + // so we can now update `buf_head` to reflect the new position + // SAFETY: we have just called `uzlib_uncompress` + self.data.borrow_mut().advance(&self.uncomp); + + res + }; + + // Clear the source read callback (just for safety) + self.uncomp.source_read_cb_context = core::ptr::null_mut(); + + match res { + 0 => Ok(false), + 1 => Ok(true), + _ => Err(()), + } + } /// Skips a specified number of bytes (`nbytes`) in the uncompressed stream. /// @@ -65,8 +218,25 @@ impl<'a> UzlibContext<'a> { for i in (0..nbytes).step_by(sink.len()) { let chunk_len = core::cmp::min(sink.len(), nbytes - i); let chunk = &mut sink[0..chunk_len]; - result = self.uncompress(chunk)?; + result = self.read(chunk)?; } Ok(result) } } + +/// This function is called by the uzlib library to read more data from the +/// input stream. +unsafe extern "C" fn zlib_reader_callback(uncomp: *mut ffi::uzlib_uncomp) -> i32 { + // SAFETY: we assume that passed-in uncomp is not null and that we own it + // exclusively (ensured by passing it as &mut into uzlib_uncompress()) + let uncomp = unwrap!(unsafe { uncomp.as_mut() }); + let ctx = uncomp.source_read_cb_context as *const RefCell; + // SAFETY: we assume that ctx is a valid pointer to the refcell holding the + // source data + let mut ctx = unwrap!(unsafe { ctx.as_ref() }).borrow_mut(); + + match ctx.reader_callback(uncomp) { + Some(byte) => byte as i32, + None => -1, // EOF + } +} diff --git a/core/embed/rust/src/trezorhal/wordlist.rs b/core/embed/rust/src/trezorhal/wordlist.rs index ecfd497e5c..a68a4b5670 100644 --- a/core/embed/rust/src/trezorhal/wordlist.rs +++ b/core/embed/rust/src/trezorhal/wordlist.rs @@ -1,6 +1,5 @@ use super::ffi; -use core::cmp::Ordering; -use cstr_core::CStr; +use core::{cmp::Ordering, ffi::CStr}; /// Holds all the possible words with the possibility to interact /// with the "list" - filtering it further, getting their count, etc. @@ -102,7 +101,7 @@ unsafe fn from_utf8_unchecked<'a>(word: *const cty::c_char) -> &'a str { // SAFETY: caller must pass a valid 0-terminated UTF-8 string. // This assumption holds for usage on words of the BIP-39/SLIP-39 wordlists. unsafe { - let word = CStr::from_ptr(word); + let word = CStr::from_ptr(word as _); core::str::from_utf8_unchecked(word.to_bytes()) } } diff --git a/core/embed/rust/src/ui/animation.rs b/core/embed/rust/src/ui/animation.rs index 7469491398..af0709c841 100644 --- a/core/embed/rust/src/ui/animation.rs +++ b/core/embed/rust/src/ui/animation.rs @@ -4,6 +4,7 @@ use crate::{ }; /// Running, time-based linear progression of a value. +#[derive(Clone)] pub struct Animation { /// Starting value. pub from: T, @@ -56,7 +57,11 @@ impl Animation { } else { // Duration is too large to be added to an `Instant`. #[cfg(feature = "ui_debug")] - panic!("offset is too large"); + fatal_error!("Offset is too large"); } } + + pub fn finished(&self, now: Instant) -> bool { + self.elapsed(now) >= self.duration + } } diff --git a/core/embed/rust/src/ui/api/bootloader_c.rs b/core/embed/rust/src/ui/api/bootloader_c.rs index 9eac86cd28..30bb2524b5 100644 --- a/core/embed/rust/src/ui/api/bootloader_c.rs +++ b/core/embed/rust/src/ui/api/bootloader_c.rs @@ -13,6 +13,7 @@ extern "C" fn screen_welcome() { } #[no_mangle] +#[cfg(not(feature = "new_rendering"))] extern "C" fn bld_continue_label(bg_color: cty::uint16_t) { ModelUI::bld_continue_label(bg_color.into()); } @@ -39,6 +40,7 @@ extern "C" fn screen_install_confirm( fingerprint: *const cty::uint8_t, should_keep_seed: bool, is_newvendor: bool, + is_newinstall: bool, version_cmp: cty::c_int, ) -> u32 { let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) }); @@ -57,6 +59,7 @@ extern "C" fn screen_install_confirm( fingerprint_str, should_keep_seed, is_newvendor, + is_newinstall, version_cmp, ) } @@ -101,6 +104,28 @@ extern "C" fn screen_boot_stage_1(fading: bool) { ModelUI::screen_boot_stage_1(fading) } +#[no_mangle] +#[cfg(feature = "new_rendering")] +extern "C" fn screen_boot( + warning: bool, + vendor_str: *const cty::c_char, + vendor_str_len: usize, + version: u32, + vendor_img: *const cty::c_void, + vendor_img_len: usize, + wait: i32, +) { + let vendor_str = unsafe { from_c_array(vendor_str, vendor_str_len) }; + let vendor_img = + unsafe { core::slice::from_raw_parts(vendor_img as *const u8, vendor_img_len) }; + + // Splits a version stored as a u32 into four numbers + // starting with the major version. + let version = version.to_le_bytes(); + + ModelUI::screen_boot(warning, vendor_str, version, vendor_img, wait); +} + #[no_mangle] extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) { ModelUI::screen_wipe_progress(progress, initialize) diff --git a/core/embed/rust/src/ui/api/common_c.rs b/core/embed/rust/src/ui/api/common_c.rs index 51a427188d..ccbed0d3a3 100644 --- a/core/embed/rust/src/ui/api/common_c.rs +++ b/core/embed/rust/src/ui/api/common_c.rs @@ -1,26 +1,28 @@ //! Reexporting the `screens` module according to the //! current feature (Trezor model) +use crate::ui::ui_features::{ModelUI, UIFeaturesCommon}; + +#[cfg(not(feature = "new_rendering"))] use crate::ui::{ component::image::Image, display::{Color, Icon}, geometry::{Alignment2D, Point}, - ui_features::{ModelUI, UIFeaturesCommon}, }; -use crate::ui::util::from_c_str; +use crate::{trezorhal::fatal_error, ui::util::from_c_str}; #[no_mangle] -extern "C" fn screen_fatal_error_rust( +extern "C" fn error_shutdown_rust( title: *const cty::c_char, msg: *const cty::c_char, footer: *const cty::c_char, -) { +) -> ! { let title = unsafe { from_c_str(title) }.unwrap_or(""); let msg = unsafe { from_c_str(msg) }.unwrap_or(""); let footer = unsafe { from_c_str(footer) }.unwrap_or(""); - ModelUI::screen_fatal_error(title, msg, footer); + fatal_error::error_shutdown(title, msg, footer) } #[no_mangle] @@ -29,6 +31,7 @@ extern "C" fn screen_boot_stage_2() { } #[no_mangle] +#[cfg(not(feature = "new_rendering"))] extern "C" fn display_icon( x: cty::int16_t, y: cty::int16_t, @@ -48,6 +51,7 @@ extern "C" fn display_icon( } #[no_mangle] +#[cfg(not(feature = "new_rendering"))] extern "C" fn display_image( x: cty::int16_t, y: cty::int16_t, diff --git a/core/embed/rust/src/ui/backlight.rs b/core/embed/rust/src/ui/backlight.rs new file mode 100644 index 0000000000..98f6aff269 --- /dev/null +++ b/core/embed/rust/src/ui/backlight.rs @@ -0,0 +1,45 @@ +use crate::{ + error::Error, + micropython::{ + ffi, macros::obj_type, obj::Obj, qstr::Qstr, simple_type::SimpleTypeObj, typ::Type, util, + }, + ui::{ui_features::ModelUI, UIFeaturesCommon}, +}; + +/* + * This whole module should be removed, in favor of fully + * moving backlight control into Rust. Relatively easy to do, but not + * necessary right now. Filed as https://github.com/trezor/trezor-firmware/issues/3849 + * + * Consider this module temporary. (yeah yeah everyone knows "temporary" + * things stay forever. Written in May 2024.) + */ + +static BACKLIGHT_LEVELS_TYPE: Type = obj_type! { + name: Qstr::MP_QSTR_BacklightLevels, + attr_fn: backlight_levels_attr, +}; + +unsafe extern "C" fn backlight_levels_attr(_self_in: Obj, attr: ffi::qstr, dest: *mut Obj) { + let block = || { + let arg = unsafe { dest.read() }; + if !arg.is_null() { + // Null destination would mean a `setattr`. + return Err(Error::TypeError); + } + let attr = Qstr::from_u16(attr as _); + let value = match attr { + Qstr::MP_QSTR_NONE => ModelUI::get_backlight_none(), + Qstr::MP_QSTR_NORMAL => ModelUI::get_backlight_normal(), + Qstr::MP_QSTR_LOW => ModelUI::get_backlight_low(), + Qstr::MP_QSTR_DIM => ModelUI::get_backlight_dim(), + Qstr::MP_QSTR_MAX => ModelUI::get_backlight_max(), + _ => return Err(Error::AttributeError(attr)), + }; + unsafe { dest.write(value.into()) }; + Ok(()) + }; + unsafe { util::try_or_raise(block) } +} + +pub static BACKLIGHT_LEVELS_OBJ: SimpleTypeObj = SimpleTypeObj::new(&BACKLIGHT_LEVELS_TYPE); diff --git a/core/embed/rust/src/ui/button_request.rs b/core/embed/rust/src/ui/button_request.rs new file mode 100644 index 0000000000..58fe5ff178 --- /dev/null +++ b/core/embed/rust/src/ui/button_request.rs @@ -0,0 +1,58 @@ +use crate::strutil::TString; +use num_traits::FromPrimitive; + +// ButtonRequestType from messages-common.proto +// Eventually this should be generated +#[derive(Clone, Copy, FromPrimitive)] +#[repr(u16)] +pub enum ButtonRequestCode { + Other = 1, + FeeOverThreshold = 2, + ConfirmOutput = 3, + ResetDevice = 4, + ConfirmWord = 5, + WipeDevice = 6, + ProtectCall = 7, + SignTx = 8, + FirmwareCheck = 9, + Address = 10, + PublicKey = 11, + MnemonicWordCount = 12, + MnemonicInput = 13, + UnknownDerivationPath = 15, + RecoveryHomepage = 16, + Success = 17, + Warning = 18, + PassphraseEntry = 19, + PinEntry = 20, +} + +impl ButtonRequestCode { + pub fn num(&self) -> u16 { + *self as u16 + } + + pub fn with_name(self, name: &'static str) -> ButtonRequest { + ButtonRequest::new(self, name.into()) + } + + pub fn from(i: u16) -> Self { + unwrap!(Self::from_u16(i)) + } +} + +#[derive(Clone)] +pub struct ButtonRequest { + pub code: ButtonRequestCode, + pub name: TString<'static>, +} + +impl ButtonRequest { + pub fn new(code: ButtonRequestCode, name: TString<'static>) -> Self { + ButtonRequest { code, name } + } + + pub fn from_num(code: u16, name: TString<'static>) -> Self { + ButtonRequest::new(ButtonRequestCode::from(code), name) + } +} diff --git a/core/embed/rust/src/ui/component/bar.rs b/core/embed/rust/src/ui/component/bar.rs new file mode 100644 index 0000000000..2ac5556cfb --- /dev/null +++ b/core/embed/rust/src/ui/component/bar.rs @@ -0,0 +1,57 @@ +use crate::ui::{ + component::{Component, Event, EventCtx, Never}, + display, + display::Color, + geometry::Rect, + shape, + shape::Renderer, +}; + +pub struct Bar { + area: Rect, + color: Color, + bg_color: Color, + radius: i16, +} + +impl Bar { + pub fn new(color: Color, bg_color: Color, radius: i16) -> Self { + Self { + area: Rect::zero(), + color, + bg_color, + radius, + } + } +} + +impl Component for Bar { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.area = bounds; + self.area + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) { + display::rect_fill_rounded(self.area, self.color, self.bg_color, self.radius as u8); + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + shape::Bar::new(self.area) + .with_bg(self.color) + .with_radius(self.radius) + .render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for Bar { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("Bar"); + } +} diff --git a/core/embed/rust/src/ui/component/base.rs b/core/embed/rust/src/ui/component/base.rs index 6703440b7d..0b96581c2e 100644 --- a/core/embed/rust/src/ui/component/base.rs +++ b/core/embed/rust/src/ui/component/base.rs @@ -3,22 +3,26 @@ use core::mem; use heapless::Vec; use crate::{ - strutil::TString, + strutil::{ShortString, TString}, time::Duration, ui::{ - component::{maybe::PaintOverlapping, MsgMap}, - display::{self, Color}, + button_request::{ButtonRequest, ButtonRequestCode}, + component::{maybe::PaintOverlapping, MsgMap, PageMap}, + display::Color, geometry::{Offset, Rect}, + shape::Renderer, }, }; #[cfg(feature = "button")] use crate::ui::event::ButtonEvent; -#[cfg(feature = "touch")] -use crate::ui::event::TouchEvent; use crate::ui::event::USBEvent; +#[cfg(feature = "touch")] +use crate::ui::event::{SwipeEvent, TouchEvent}; use super::Paginate; +#[cfg(feature = "touch")] +use super::SwipeDirection; /// Type used by components that do not return any messages. /// @@ -61,9 +65,7 @@ pub trait Component { /// the `Child` wrapper. fn paint(&mut self); - #[cfg(feature = "ui_bounds")] - /// Report current paint bounds of this component. Used for debugging. - fn bounds(&self, _sink: &mut dyn FnMut(Rect)) {} + fn render<'s>(&'s self, _target: &mut impl Renderer<'s>); } /// Components should always avoid unnecessary overpaint to prevent obvious @@ -71,13 +73,14 @@ pub trait Component { /// dirty flag for it. Any mutation of `T` has to happen through the `mutate` /// accessor, `T` can then request a paint call to be scheduled later by calling /// `EventCtx::request_paint` in its `event` pass. +#[derive(Clone)] pub struct Child { component: T, marked_for_paint: bool, } impl Child { - pub fn new(component: T) -> Self { + pub const fn new(component: T) -> Self { Self { component, marked_for_paint: true, @@ -154,9 +157,8 @@ where } } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.component.bounds(sink) + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.component.render(target); } } @@ -196,80 +198,6 @@ where } } -/// Same as `Child` but also handles screen clearing when layout is first -/// painted. -pub struct Root { - inner: Child, - marked_for_clear: bool, -} - -impl Root { - pub fn new(component: T) -> Self { - Self { - inner: Child::new(component), - marked_for_clear: true, - } - } - - pub fn inner(&self) -> &Child { - &self.inner - } - - pub fn skip_paint(&mut self) { - self.inner.skip_paint() - } - - pub fn clear_screen(&mut self) { - self.marked_for_clear = true; - } -} - -impl Component for Root -where - T: Component, -{ - type Msg = T::Msg; - - fn place(&mut self, bounds: Rect) -> Rect { - self.inner.place(bounds) - } - - fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - let msg = self.inner.event(ctx, event); - if ctx.needs_repaint_root() { - self.marked_for_clear = true; - let mut dummy_ctx = EventCtx::new(); - let paint_msg = self.inner.event(&mut dummy_ctx, Event::RequestPaint); - assert!(paint_msg.is_none()); - assert!(dummy_ctx.timers.is_empty()); - } - msg - } - - fn paint(&mut self) { - if self.marked_for_clear && self.inner.will_paint() { - self.marked_for_clear = false; - display::clear() - } - self.inner.paint(); - } - - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.inner.bounds(sink) - } -} - -#[cfg(feature = "ui_debug")] -impl crate::trace::Trace for Root -where - T: crate::trace::Trace, -{ - fn trace(&self, t: &mut dyn crate::trace::Tracer) { - self.inner.trace(t) - } -} - impl Component for (T, U) where T: Component, @@ -292,10 +220,9 @@ where self.1.paint(); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.0.bounds(sink); - self.1.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.0.render(target); + self.1.render(target); } } @@ -341,11 +268,10 @@ where self.2.paint(); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.0.bounds(sink); - self.1.bounds(sink); - self.2.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.0.render(target); + self.1.render(target); + self.2.render(target); } } @@ -368,23 +294,23 @@ where } } + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + if let Some(ref c) = self { + c.render(target) + } + } + fn place(&mut self, bounds: Rect) -> Rect { match self { Some(ref mut c) => c.place(bounds), _ => bounds.with_size(Offset::zero()), } } - - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - if let Some(ref c) = self { - c.bounds(sink) - } - } } pub trait ComponentExt: Sized { fn map(self, func: F) -> MsgMap; + fn with_pages(self, func: F) -> PageMap; fn into_child(self) -> Child; fn request_complete_repaint(&mut self, ctx: &mut EventCtx); } @@ -397,6 +323,10 @@ where MsgMap::new(self, func) } + fn with_pages(self, func: F) -> PageMap { + PageMap::new(self, func) + } + fn into_child(self) -> Child { Child::new(self) } @@ -406,7 +336,7 @@ where // Messages raised during a `RequestPaint` dispatch are not propagated, let's // make sure we don't do that. #[cfg(feature = "ui_debug")] - panic!("cannot raise messages during RequestPaint"); + fatal_error!("Cannot raise messages during RequestPaint"); } // Make sure to at least a propagate the paint flag upwards (in case there are // no `Child` instances in `self`, paint would not get automatically requested @@ -416,6 +346,20 @@ where } #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] +pub enum AttachType { + /// Initial attach, redraw the whole screen + Initial, + /// The layout is already rendered on display, resume any animation + /// where we left off. The animation state is expected to be stored locally + /// in the given component. + Resume, + #[cfg(feature = "touch")] + Swipe(SwipeDirection), +} + +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub enum Event { #[cfg(feature = "button")] Button(ButtonEvent), @@ -429,13 +373,17 @@ pub enum Event { Progress(u16, TString<'static>), /// Component has been attached to component tree. This event is sent once /// before any other events. - Attach, + Attach(AttachType), /// Internally-handled event to inform all `Child` wrappers in a sub-tree to /// get scheduled for painting. RequestPaint, + /// Swipe and transition events + #[cfg(feature = "touch")] + Swipe(SwipeEvent), } #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub struct TimerToken(u32); impl TimerToken { @@ -458,7 +406,11 @@ pub struct EventCtx { paint_requested: bool, anim_frame_scheduled: bool, page_count: Option, + button_request: Option, root_repaint_requested: bool, + swipe_disable_req: bool, + swipe_enable_req: bool, + transition_out: Option, } impl EventCtx { @@ -466,7 +418,7 @@ impl EventCtx { pub const ANIM_FRAME_TIMER: TimerToken = TimerToken(1); /// How long into the future we should schedule the animation frame timer. - const ANIM_FRAME_DEADLINE: Duration = Duration::from_millis(18); + const ANIM_FRAME_DEADLINE: Duration = Duration::from_millis(1); // 0 == `TimerToken::INVALID`, // 1 == `Self::ANIM_FRAME_TIMER`. @@ -484,7 +436,11 @@ impl EventCtx { * `Child::marked_for_paint` being true. */ anim_frame_scheduled: false, page_count: None, + button_request: None, root_repaint_requested: false, + swipe_disable_req: false, + swipe_enable_req: false, + transition_out: None, } } @@ -497,7 +453,7 @@ impl EventCtx { /// Returns `true` if we should first perform a place traversal before /// processing events or painting. - pub fn needs_place_before_next_event_or_paint(&self) -> bool { + pub fn needs_place(&self) -> bool { self.place_requested } @@ -531,26 +487,66 @@ impl EventCtx { self.root_repaint_requested } + pub fn needs_repaint(&self) -> bool { + self.paint_requested + } + pub fn set_page_count(&mut self, count: usize) { - #[cfg(feature = "ui_debug")] - assert!(self.page_count.is_none()); + // #[cfg(feature = "ui_debug")] + // assert!(self.page_count.unwrap_or(count) == count); self.page_count = Some(count); } + pub fn map_page_count(&mut self, func: impl Fn(usize) -> usize) { + self.page_count = Some(func(self.page_count.unwrap_or(1))); + } + pub fn page_count(&self) -> Option { self.page_count } + pub fn send_button_request(&mut self, code: ButtonRequestCode, name: TString<'static>) { + #[cfg(feature = "ui_debug")] + assert!(self.button_request.is_none()); + self.button_request = Some(ButtonRequest::new(code, name)); + } + + pub fn button_request(&mut self) -> Option { + self.button_request.take() + } + pub fn pop_timer(&mut self) -> Option<(TimerToken, Duration)> { self.timers.pop() } + pub fn disable_swipe(&mut self) { + self.swipe_disable_req = true; + } + + pub fn disable_swipe_requested(&self) -> bool { + self.swipe_disable_req + } + + pub fn enable_swipe(&mut self) { + self.swipe_enable_req = true; + } + + pub fn enable_swipe_requested(&self) -> bool { + self.swipe_enable_req + } + pub fn clear(&mut self) { self.place_requested = false; self.paint_requested = false; self.anim_frame_scheduled = false; self.page_count = None; + #[cfg(feature = "ui_debug")] + assert!(self.button_request.is_none()); + self.button_request = None; self.root_repaint_requested = false; + self.swipe_disable_req = false; + self.swipe_enable_req = false; + self.transition_out = None; } fn register_timer(&mut self, token: TimerToken, deadline: Duration) { @@ -558,7 +554,7 @@ impl EventCtx { // The timer queue is full, this would be a development error in the layout // layer. Let's panic in the debug env. #[cfg(feature = "ui_debug")] - panic!("timer queue is full"); + fatal_error!("Timer queue is full"); } } @@ -573,4 +569,43 @@ impl EventCtx { .unwrap_or(Self::STARTING_TIMER_TOKEN); token } + + pub fn set_transition_out(&mut self, attach_type: AttachType) { + self.transition_out = Some(attach_type); + } + + pub fn get_transition_out(&self) -> Option { + self.transition_out + } +} + +/// Component::Msg for component parts of a swipe flow. Converting results of +/// different screens to a shared type makes things easier to work with. +/// +/// Also currently the type for message emitted by Flow::event to +/// micropython. They don't need to be the same. +#[derive(Clone)] +pub enum FlowMsg { + Confirmed, + Cancelled, + Info, + Choice(usize), + Text(ShortString), +} + +#[cfg(feature = "micropython")] +impl TryFrom for crate::micropython::obj::Obj { + type Error = crate::error::Error; + + fn try_from(val: FlowMsg) -> Result { + match val { + FlowMsg::Confirmed => Ok(crate::ui::layout::result::CONFIRMED.as_obj()), + FlowMsg::Cancelled => Ok(crate::ui::layout::result::CANCELLED.as_obj()), + FlowMsg::Info => Ok(crate::ui::layout::result::INFO.as_obj()), + FlowMsg::Choice(i) => { + Ok((crate::ui::layout::result::CONFIRMED.as_obj(), i.try_into()?).try_into()?) + } + FlowMsg::Text(_s) => panic!(), + } + } } diff --git a/core/embed/rust/src/ui/component/border.rs b/core/embed/rust/src/ui/component/border.rs index e61cf381a6..a8b93ecd84 100644 --- a/core/embed/rust/src/ui/component/border.rs +++ b/core/embed/rust/src/ui/component/border.rs @@ -1,5 +1,8 @@ use super::{Component, Event, EventCtx}; -use crate::ui::geometry::{Insets, Rect}; +use crate::ui::{ + geometry::{Insets, Rect}, + shape::Renderer, +}; pub struct Border { border: Insets, @@ -39,9 +42,8 @@ where self.inner.paint() } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.inner.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); } } @@ -54,3 +56,13 @@ where self.inner.trace(t) } } + +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl ComponentMsgObj for super::Border { + fn msg_try_into_obj(&self, msg: Self::Msg) -> Result { + self.inner().msg_try_into_obj(msg) + } + } +} diff --git a/core/embed/rust/src/ui/component/button_request.rs b/core/embed/rust/src/ui/component/button_request.rs new file mode 100644 index 0000000000..273f9858ed --- /dev/null +++ b/core/embed/rust/src/ui/component/button_request.rs @@ -0,0 +1,108 @@ +use crate::ui::{ + button_request::ButtonRequest, + component::{Component, Event, EventCtx}, + geometry::Rect, +}; + +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +use crate::ui::component::swipe_detect::SwipeConfig; + +/// Component that sends a ButtonRequest after receiving Event::Attach. The +/// request is either sent only once or on every Event::Attach configured by +/// `policy`. +#[derive(Clone)] +pub struct SendButtonRequest { + button_request: Option, + pub inner: T, + policy: SendButtonRequestPolicy, +} + +#[derive(Clone)] +pub enum SendButtonRequestPolicy { + OnAttachOnce, + OnAttachAlways, +} + +impl SendButtonRequest { + pub const fn new( + button_request: ButtonRequest, + inner: T, + policy: SendButtonRequestPolicy, + ) -> Self { + Self { + button_request: Some(button_request), + inner, + policy, + } + } +} + +impl Component for SendButtonRequest { + type Msg = T::Msg; + + fn place(&mut self, bounds: Rect) -> Rect { + self.inner.place(bounds) + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if matches!(event, Event::Attach(_)) { + match self.policy { + SendButtonRequestPolicy::OnAttachOnce => { + if let Some(br) = self.button_request.take() { + ctx.send_button_request(br.code, br.name) + } + } + SendButtonRequestPolicy::OnAttachAlways => { + if let Some(br) = self.button_request.clone() { + ctx.send_button_request(br.code, br.name); + } + } + } + } + self.inner.event(ctx, event) + } + + fn paint(&mut self) { + self.inner.paint() + } + + fn render<'s>(&'s self, target: &mut impl crate::ui::shape::Renderer<'s>) { + self.inner.render(target) + } +} + +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +impl crate::ui::flow::Swipable for SendButtonRequest { + fn get_swipe_config(&self) -> SwipeConfig { + self.inner.get_swipe_config() + } + + fn get_internal_page_count(&self) -> usize { + self.inner.get_internal_page_count() + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for SendButtonRequest { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + self.inner.trace(t) + } +} + +pub trait ButtonRequestExt { + fn one_button_request(self, br: ButtonRequest) -> SendButtonRequest + where + Self: Sized, + { + SendButtonRequest::new(br, self, SendButtonRequestPolicy::OnAttachOnce) + } + + fn repeated_button_request(self, br: ButtonRequest) -> SendButtonRequest + where + Self: Sized, + { + SendButtonRequest::new(br, self, SendButtonRequestPolicy::OnAttachAlways) + } +} + +impl ButtonRequestExt for T {} diff --git a/core/embed/rust/src/ui/component/cached_jpeg.rs b/core/embed/rust/src/ui/component/cached_jpeg.rs new file mode 100644 index 0000000000..600c02f8cf --- /dev/null +++ b/core/embed/rust/src/ui/component/cached_jpeg.rs @@ -0,0 +1,93 @@ +use crate::{ + io::BinaryData, + ui::{ + component::{Component, Event, EventCtx, Never}, + display::image::ImageInfo, + geometry::{Offset, Point, Rect}, + shape, + shape::{render_on_canvas, ImageBuffer, Renderer, Rgb565Canvas}, + }, +}; + +pub struct CachedJpeg { + area: Rect, + image_size: Offset, + jpeg: ImageBuffer>, + scale: u8, +} + +impl CachedJpeg { + pub fn new(image: BinaryData<'static>, scale: u8) -> Self { + let size = match ImageInfo::parse(image) { + ImageInfo::Jpeg(info) => { + if info.mcu_height() > 16 { + Offset::zero() + } else { + Offset::new(info.width(), info.height()) + } + } + _ => Offset::zero(), + }; + + let mut buf = unwrap!(ImageBuffer::new(size), "no image buf"); + + render_on_canvas(buf.canvas(), None, |target| { + shape::JpegImage::new_image(Point::zero(), image) + .with_scale(scale) + .render(target); + }); + + Self { + area: Rect::zero(), + image_size: size, + jpeg: buf, + scale, + } + } +} + +impl Component for CachedJpeg { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.area = bounds; + self.area + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) {} + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let off = Offset::new( + self.image_size.x / (2 << self.scale), + self.image_size.y / (2 << self.scale), + ); + let pos = self.area.center() - off; + + shape::RawImage::new( + Rect::from_top_left_and_size(pos, self.image_size * (1.0 / (1 << self.scale) as f32)), + self.jpeg.view(), + ) + .render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for CachedJpeg { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("CachedJpeg"); + } +} + +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl ComponentMsgObj for super::CachedJpeg { + fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { + unreachable!(); + } + } +} diff --git a/core/embed/rust/src/ui/component/connect.rs b/core/embed/rust/src/ui/component/connect.rs index 5faa389242..3d7897bdf0 100644 --- a/core/embed/rust/src/ui/component/connect.rs +++ b/core/embed/rust/src/ui/component/connect.rs @@ -3,7 +3,8 @@ use crate::{ ui::{ component::{Component, Event, EventCtx, Never, Pad}, display::{self, Color, Font}, - geometry::{Offset, Rect}, + geometry::{Alignment, Offset, Rect}, + shape::{self, Renderer}, }, }; @@ -55,6 +56,20 @@ impl Component for Connect { ) }); } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let font = Font::NORMAL; + + self.bg.render(target); + + self.message.map(|t| { + shape::Text::new(self.bg.area.center() + Offset::y(font.text_height() / 2), t) + .with_fg(self.fg) + .with_font(font) + .with_align(Alignment::Center) + .render(target); + }); + } } #[cfg(feature = "micropython")] diff --git a/core/embed/rust/src/ui/component/empty.rs b/core/embed/rust/src/ui/component/empty.rs index ce2a3b8834..cce48b0cec 100644 --- a/core/embed/rust/src/ui/component/empty.rs +++ b/core/embed/rust/src/ui/component/empty.rs @@ -1,6 +1,7 @@ use super::{Component, Event, EventCtx, Never}; -use crate::ui::geometry::Rect; +use crate::ui::{geometry::Rect, shape::Renderer}; +#[derive(Clone)] pub struct Empty; impl Component for Empty { @@ -15,6 +16,8 @@ impl Component for Empty { } fn paint(&mut self) {} + + fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {} } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/image.rs b/core/embed/rust/src/ui/component/image.rs index 41c1a68839..b51a54f63f 100644 --- a/core/embed/rust/src/ui/component/image.rs +++ b/core/embed/rust/src/ui/component/image.rs @@ -6,6 +6,8 @@ use crate::ui::{ Color, Icon, }, geometry::{Alignment2D, Offset, Point, Rect}, + shape, + shape::Renderer, }; #[derive(PartialEq, Eq, Clone, Copy)] @@ -48,12 +50,10 @@ impl Component for Image { self.draw(self.area.center(), Alignment2D::CENTER); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(Rect::from_center_and_size( - self.area.center(), - self.toif.size(), - )); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + shape::ToifImage::new(self.area.center(), self.toif) + .with_align(Alignment2D::CENTER) + .render(target); } } @@ -130,12 +130,13 @@ impl Component for BlendedImage { self.paint_image(); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(Rect::from_top_left_and_size( - self.bg_top_left, - self.bg.toif.size(), - )); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + shape::ToifImage::new(self.bg_top_left, self.bg.toif) + .with_fg(self.bg_color) + .render(target); + shape::ToifImage::new(self.bg_top_left + self.fg_offset, self.fg.toif) + .with_fg(self.fg_color) + .render(target); } } diff --git a/core/embed/rust/src/ui/component/jpeg.rs b/core/embed/rust/src/ui/component/jpeg.rs new file mode 100644 index 0000000000..1285c6003b --- /dev/null +++ b/core/embed/rust/src/ui/component/jpeg.rs @@ -0,0 +1,74 @@ +use crate::{ + io::BinaryData, + ui::{ + component::{Component, Event, EventCtx, Never}, + display, + geometry::{Alignment2D, Offset, Rect}, + shape, + shape::Renderer, + }, +}; + +pub struct Jpeg { + area: Rect, + image: BinaryData<'static>, + scale: u8, +} + +impl Jpeg { + pub fn new(image: BinaryData<'static>, scale: u8) -> Self { + Self { + area: Rect::zero(), + image, + scale, + } + } +} + +impl Component for Jpeg { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.area = bounds; + self.area + } + + fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { + None + } + + fn paint(&mut self) { + // SAFETY: We expect no existing mutable reference. Resulting reference is + // discarded before returning to micropython. + let jpeg_data = unsafe { self.image.data() }; + + if let Some((size, _)) = display::tjpgd::jpeg_info(jpeg_data) { + let off = Offset::new(size.x / (2 << self.scale), size.y / (2 << self.scale)); + display::tjpgd::jpeg(jpeg_data, self.area.center() - off, self.scale); + } + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + shape::JpegImage::new_image(self.area.center(), self.image) + .with_align(Alignment2D::CENTER) + .with_scale(self.scale) + .render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for Jpeg { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("Jpeg"); + } +} + +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl ComponentMsgObj for super::Jpeg { + fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { + unreachable!(); + } + } +} diff --git a/core/embed/rust/src/ui/component/label.rs b/core/embed/rust/src/ui/component/label.rs index 55364dcc98..624eb75ae0 100644 --- a/core/embed/rust/src/ui/component/label.rs +++ b/core/embed/rust/src/ui/component/label.rs @@ -4,11 +4,13 @@ use crate::{ component::{Component, Event, EventCtx, Never}, display::Font, geometry::{Alignment, Insets, Offset, Point, Rect}, + shape::Renderer, }, }; use super::{text::TextStyle, TextLayout}; +#[derive(Clone)] pub struct Label<'a> { text: TString<'a>, layout: TextLayout, @@ -16,7 +18,7 @@ pub struct Label<'a> { } impl<'a> Label<'a> { - pub fn new(text: TString<'a>, align: Alignment, style: TextStyle) -> Self { + pub const fn new(text: TString<'a>, align: Alignment, style: TextStyle) -> Self { Self { text, layout: TextLayout::new(style).with_align(align), @@ -24,23 +26,38 @@ impl<'a> Label<'a> { } } - pub fn left_aligned(text: TString<'a>, style: TextStyle) -> Self { + pub const fn left_aligned(text: TString<'a>, style: TextStyle) -> Self { Self::new(text, Alignment::Start, style) } - pub fn right_aligned(text: TString<'a>, style: TextStyle) -> Self { + pub const fn right_aligned(text: TString<'a>, style: TextStyle) -> Self { Self::new(text, Alignment::End, style) } - pub fn centered(text: TString<'a>, style: TextStyle) -> Self { + pub const fn centered(text: TString<'a>, style: TextStyle) -> Self { Self::new(text, Alignment::Center, style) } - pub fn vertically_centered(mut self) -> Self { + pub const fn top_aligned(mut self) -> Self { + self.vertical = Alignment::Start; + self + } + + pub const fn vertically_centered(mut self) -> Self { self.vertical = Alignment::Center; self } + pub const fn bottom_aligned(mut self) -> Self { + self.vertical = Alignment::End; + self + } + + pub const fn styled(mut self, style: TextStyle) -> Self { + self.layout.style = style; + self + } + pub fn text(&self) -> &TString<'a> { &self.text } @@ -49,6 +66,10 @@ impl<'a> Label<'a> { self.text = text; } + pub fn set_style(&mut self, style: TextStyle) { + self.layout.style = style; + } + pub fn font(&self) -> Font { self.layout.style.text_font } @@ -57,7 +78,7 @@ impl<'a> Label<'a> { self.layout.bounds } - pub fn alignment(&self) -> Alignment { + pub const fn alignment(&self) -> Alignment { self.layout.align } @@ -87,6 +108,11 @@ impl<'a> Label<'a> { }; Rect::from_bottom_left_and_size(baseline, Offset::new(width, height)) } + + pub fn render_with_alpha<'s>(&self, target: &mut impl Renderer<'s>, alpha: u8) { + self.text + .map(|c| self.layout.render_text_with_alpha(c, target, alpha)); + } } impl Component for Label<'_> { @@ -114,9 +140,8 @@ impl Component for Label<'_> { self.text.map(|c| self.layout.render_text(c)); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.layout.bounds) + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.text.map(|c| self.layout.render_text2(c, target)); } } diff --git a/core/embed/rust/src/ui/component/map.rs b/core/embed/rust/src/ui/component/map.rs index 867d51f59f..3fc5c469d4 100644 --- a/core/embed/rust/src/ui/component/map.rs +++ b/core/embed/rust/src/ui/component/map.rs @@ -1,5 +1,8 @@ use super::{Component, Event, EventCtx}; -use crate::ui::geometry::Rect; +use crate::ui::{geometry::Rect, shape::Renderer}; + +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +use crate::ui::component::swipe_detect::SwipeConfig; pub struct MsgMap { inner: T, @@ -31,9 +34,21 @@ where self.inner.paint() } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.inner.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); + } +} + +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +impl crate::ui::flow::Swipable for MsgMap +where + T: Component + crate::ui::flow::Swipable, +{ + fn get_swipe_config(&self) -> SwipeConfig { + self.inner.get_swipe_config() + } + fn get_internal_page_count(&self) -> usize { + self.inner.get_internal_page_count() } } @@ -46,3 +61,63 @@ where self.inner.trace(t) } } + +pub struct PageMap { + inner: T, + func: F, +} + +impl PageMap { + pub fn new(inner: T, func: F) -> Self { + Self { inner, func } + } +} + +impl Component for PageMap +where + T: Component, + F: Fn(usize) -> usize, +{ + type Msg = T::Msg; + + fn place(&mut self, bounds: Rect) -> Rect { + self.inner.place(bounds) + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + let res = self.inner.event(ctx, event); + ctx.map_page_count(&self.func); + res + } + + fn paint(&mut self) { + self.inner.paint() + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for PageMap +where + T: Component + crate::trace::Trace, +{ + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + self.inner.trace(t) + } +} + +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +impl crate::ui::flow::Swipable for PageMap +where + T: Component + crate::ui::flow::Swipable, +{ + fn get_swipe_config(&self) -> SwipeConfig { + self.inner.get_swipe_config() + } + fn get_internal_page_count(&self) -> usize { + self.inner.get_internal_page_count() + } +} diff --git a/core/embed/rust/src/ui/component/marquee.rs b/core/embed/rust/src/ui/component/marquee.rs index c2f39a0819..d6a91386c8 100644 --- a/core/embed/rust/src/ui/component/marquee.rs +++ b/core/embed/rust/src/ui/component/marquee.rs @@ -4,9 +4,9 @@ use crate::{ ui::{ animation::Animation, component::{Component, Event, EventCtx, Never, TimerToken}, - display, - display::{Color, Font}, - geometry::Rect, + display::{self, Color, Font}, + geometry::{Offset, Rect}, + shape::{self, Renderer}, util::animation_disabled, }, }; @@ -123,6 +123,19 @@ impl Marquee { self.text .map(|t| display::marquee(self.area, t, offset, self.font, self.fg, self.bg)); } + + pub fn render_anim<'s>(&'s self, target: &mut impl Renderer<'s>, offset: i16) { + target.in_window(self.area, &|target| { + let text_height = self.font.text_height(); + let pos = self.area.top_left() + Offset::new(offset, text_height - 1); + self.text.map(|t| { + shape::Text::new(pos, t) + .with_font(self.font) + .with_fg(self.fg) + .render(target); + }); + }); + } } impl Component for Marquee { @@ -214,6 +227,30 @@ impl Component for Marquee { } } } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let now = Instant::now(); + + match self.state { + State::Initial => { + self.render_anim(target, 0); + } + State::PauseRight => { + self.render_anim(target, self.min_offset); + } + State::PauseLeft => { + self.render_anim(target, self.max_offset); + } + _ => { + let progress = self.progress(now); + if let Some(done) = progress { + self.render_anim(target, done); + } else { + self.render_anim(target, 0); + } + } + } + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/maybe.rs b/core/embed/rust/src/ui/component/maybe.rs index 739f1ab823..e46c804de0 100644 --- a/core/embed/rust/src/ui/component/maybe.rs +++ b/core/embed/rust/src/ui/component/maybe.rs @@ -2,6 +2,7 @@ use crate::ui::{ component::{Component, ComponentExt, Event, EventCtx, Pad}, display::{self, Color}, geometry::Rect, + shape::Renderer, }; pub struct Maybe { @@ -94,10 +95,11 @@ where } } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.pad.area); - self.inner.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.pad.render(target); + if self.visible { + self.inner.render(target); + } } } diff --git a/core/embed/rust/src/ui/component/mod.rs b/core/embed/rust/src/ui/component/mod.rs index bc54734d9c..199359aed9 100644 --- a/core/embed/rust/src/ui/component/mod.rs +++ b/core/embed/rust/src/ui/component/mod.rs @@ -1,34 +1,52 @@ -#![forbid(unsafe_code)] +//#![forbid(unsafe_code)] +pub mod bar; pub mod base; pub mod border; +pub mod button_request; +#[cfg(all(feature = "jpeg", feature = "ui_image_buffer", feature = "micropython"))] +pub mod cached_jpeg; pub mod connect; pub mod empty; pub mod image; +#[cfg(all(feature = "jpeg", feature = "micropython"))] +pub mod jpeg; pub mod label; pub mod map; pub mod marquee; pub mod maybe; pub mod pad; pub mod paginated; -pub mod painter; pub mod placed; pub mod qr_code; +#[cfg(feature = "touch")] +pub mod swipe; +#[cfg(feature = "touch")] +pub mod swipe_detect; pub mod text; pub mod timeout; -pub use base::{Child, Component, ComponentExt, Event, EventCtx, Never, Root, TimerToken}; +pub use bar::Bar; +pub use base::{Child, Component, ComponentExt, Event, EventCtx, FlowMsg, Never, TimerToken}; pub use border::Border; +pub use button_request::{ButtonRequestExt, SendButtonRequest}; +#[cfg(all(feature = "jpeg", feature = "ui_image_buffer", feature = "micropython"))] +pub use cached_jpeg::CachedJpeg; pub use empty::Empty; +#[cfg(all(feature = "jpeg", feature = "micropython"))] +pub use jpeg::Jpeg; pub use label::Label; -pub use map::MsgMap; +pub use map::{MsgMap, PageMap}; pub use marquee::Marquee; pub use maybe::Maybe; pub use pad::Pad; pub use paginated::{PageMsg, Paginate}; -pub use painter::Painter; pub use placed::{FixedHeightBar, Floating, GridPlaced, Split}; pub use qr_code::Qr; +#[cfg(feature = "touch")] +pub use swipe::{Swipe, SwipeDirection}; +#[cfg(feature = "touch")] +pub use swipe_detect::{SwipeDetect, SwipeDetectMsg}; pub use text::{ formatted::FormattedText, layout::{LineBreaking, PageBreaking, TextLayout}, diff --git a/core/embed/rust/src/ui/component/pad.rs b/core/embed/rust/src/ui/component/pad.rs index b26d90d77d..fa6b5b065b 100644 --- a/core/embed/rust/src/ui/component/pad.rs +++ b/core/embed/rust/src/ui/component/pad.rs @@ -1,6 +1,8 @@ use crate::ui::{ display::{self, Color}, geometry::Rect, + shape, + shape::Renderer, }; pub struct Pad { @@ -52,4 +54,10 @@ impl Pad { display::rect_fill(self.area, self.color); } } + + pub fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + shape::Bar::new(self.area) + .with_bg(self.color) + .render(target); + } } diff --git a/core/embed/rust/src/ui/component/painter.rs b/core/embed/rust/src/ui/component/painter.rs deleted file mode 100644 index 9d6b18e37c..0000000000 --- a/core/embed/rust/src/ui/component/painter.rs +++ /dev/null @@ -1,74 +0,0 @@ -#[cfg(feature = "jpeg")] -use crate::ui::geometry::Offset; -use crate::ui::{ - component::{image::Image, Component, Event, EventCtx, Never}, - display, - geometry::{Alignment2D, Rect}, -}; - -pub struct Painter { - area: Rect, - func: F, -} - -impl Painter { - pub fn new(func: F) -> Self { - Self { - func, - area: Rect::zero(), - } - } -} - -impl Component for Painter -where - F: FnMut(Rect), -{ - type Msg = Never; - - fn place(&mut self, bounds: Rect) -> Rect { - self.area = bounds; - self.area - } - - fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option { - None - } - - fn paint(&mut self) { - (self.func)(self.area); - } - - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.area) - } -} - -#[cfg(feature = "ui_debug")] -impl crate::trace::Trace for Painter { - fn trace(&self, t: &mut dyn crate::trace::Tracer) { - t.component("Painter"); - } -} - -pub fn image_painter(image: Image) -> Painter { - let f = move |area: Rect| image.draw(area.center(), Alignment2D::CENTER); - Painter::new(f) -} - -#[cfg(feature = "jpeg")] -pub fn jpeg_painter<'a>( - image: impl Fn() -> &'a [u8], - size: Offset, - scale: u8, -) -> Painter { - let off = Offset::new(size.x / (2 << scale), size.y / (2 << scale)); - let f = move |area: Rect| display::tjpgd::jpeg(image(), area.center() - off, scale); - Painter::new(f) -} - -pub fn rect_painter(fg: display::Color, bg: display::Color) -> Painter { - let f = move |area: Rect| display::rect_fill_rounded(area, fg, bg, 2); - Painter::new(f) -} diff --git a/core/embed/rust/src/ui/component/placed.rs b/core/embed/rust/src/ui/component/placed.rs index c4a7580452..d3901203f3 100644 --- a/core/embed/rust/src/ui/component/placed.rs +++ b/core/embed/rust/src/ui/component/placed.rs @@ -1,6 +1,7 @@ use crate::ui::{ component::{Component, Event, EventCtx}, geometry::{Alignment, Alignment2D, Axis, Grid, GridCellSpan, Insets, Offset, Rect}, + shape::Renderer, }; pub struct GridPlaced { @@ -63,6 +64,10 @@ where fn paint(&mut self) { self.inner.paint() } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); + } } #[cfg(feature = "ui_debug")] @@ -106,6 +111,10 @@ where fn paint(&mut self) { self.inner.paint() } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); + } } #[cfg(feature = "ui_debug")] @@ -154,7 +163,7 @@ where let mut border = self.border; let area = match self.align.0 { Alignment::Start => bounds.split_left(self.size.x).0, - Alignment::Center => panic!("alignment not supported"), + Alignment::Center => fatal_error!("Alignment not supported"), Alignment::End => { border.x = -border.x; bounds.split_right(self.size.x).1 @@ -162,7 +171,7 @@ where }; let area = match self.align.1 { Alignment::Start => area.split_top(self.size.y).0, - Alignment::Center => panic!("alignment not supported"), + Alignment::Center => fatal_error!("Alignment not supported"), Alignment::End => { border.y = -border.y; area.split_bottom(self.size.y).1 @@ -178,6 +187,10 @@ where fn paint(&mut self) { self.inner.paint() } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target); + } } #[cfg(feature = "ui_debug")] @@ -269,6 +282,11 @@ where self.first.paint(); self.second.paint(); } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.first.render(target); + self.second.render(target); + } } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/component/qr_code.rs b/core/embed/rust/src/ui/component/qr_code.rs index e99236e3a8..f3f7fd0aae 100644 --- a/core/embed/rust/src/ui/component/qr_code.rs +++ b/core/embed/rust/src/ui/component/qr_code.rs @@ -8,6 +8,8 @@ use crate::{ constant, display::{pixeldata, pixeldata_dirty, rect_fill_rounded, set_window, Color}, geometry::{Insets, Offset, Rect}, + shape, + shape::Renderer, }, }; @@ -141,9 +143,37 @@ impl Component for Qr { Self::draw(&qr, area, self.border, scale); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.area) + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let mut outbuffer = [0u8; QR_MAX_VERSION.buffer_len()]; + let mut tempbuffer = [0u8; QR_MAX_VERSION.buffer_len()]; + + let qr = QrCode::encode_text( + self.text.as_ref(), + &mut tempbuffer, + &mut outbuffer, + QrCodeEcc::Medium, + Version::MIN, + QR_MAX_VERSION, + None, + true, + ); + let qr = unwrap!(qr); + + let scale = (self.area.width().min(self.area.height()) - self.border) / (qr.size() as i16); + let side = scale * qr.size() as i16; + let qr_area = Rect::from_center_and_size(self.area.center(), Offset::uniform(side)); + + if self.border > 0 { + shape::Bar::new(qr_area.expand(self.border)) + .with_bg(LIGHT) + .with_radius(CORNER_RADIUS as i16 + 1) // !@# + 1 to fix difference on TR + .render(target); + } + + shape::QrImage::new(qr_area, &qr) + .with_fg(LIGHT) + .with_bg(DARK) + .render(target); } } @@ -154,3 +184,13 @@ impl crate::trace::Trace for Qr { t.string("text", self.text.as_str().into()); } } + +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl ComponentMsgObj for super::Qr { + fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { + unreachable!(); + } + } +} diff --git a/core/embed/rust/src/ui/component/swipe.rs b/core/embed/rust/src/ui/component/swipe.rs new file mode 100644 index 0000000000..6e697eb132 --- /dev/null +++ b/core/embed/rust/src/ui/component/swipe.rs @@ -0,0 +1,192 @@ +use crate::ui::{ + component::{Component, Event, EventCtx}, + event::TouchEvent, + geometry::{Offset, Point, Rect}, + shape::Renderer, +}; + +#[derive(Copy, Clone, Eq, PartialEq, ToPrimitive, FromPrimitive)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] +pub enum SwipeDirection { + Up, + Down, + Left, + Right, +} + +impl SwipeDirection { + pub fn as_offset(self, size: Offset) -> Offset { + match self { + SwipeDirection::Up => Offset::y(-size.y), + SwipeDirection::Down => Offset::y(size.y), + SwipeDirection::Left => Offset::x(-size.x), + SwipeDirection::Right => Offset::x(size.x), + } + } + + pub fn iter() -> SwipeDirectionIterator { + SwipeDirectionIterator::new() + } +} + +pub struct SwipeDirectionIterator { + current: Option, +} + +impl SwipeDirectionIterator { + pub fn new() -> Self { + SwipeDirectionIterator { + current: Some(SwipeDirection::Up), + } + } +} + +impl Iterator for SwipeDirectionIterator { + type Item = SwipeDirection; + + fn next(&mut self) -> Option { + let next_state = match self.current { + Some(SwipeDirection::Up) => Some(SwipeDirection::Down), + Some(SwipeDirection::Down) => Some(SwipeDirection::Left), + Some(SwipeDirection::Left) => Some(SwipeDirection::Right), + Some(SwipeDirection::Right) => None, + None => None, + }; + + core::mem::replace(&mut self.current, next_state) + } +} + +#[derive(Clone)] +pub struct Swipe { + pub allow_up: bool, + pub allow_down: bool, + pub allow_left: bool, + pub allow_right: bool, + + origin: Option, +} + +impl Swipe { + const DISTANCE: i32 = 120; + const THRESHOLD: f32 = 0.2; + + pub fn new() -> Self { + Self { + allow_up: false, + allow_down: false, + allow_left: false, + allow_right: false, + origin: None, + } + } + + pub fn vertical() -> Self { + Self::new().up().down() + } + + pub fn horizontal() -> Self { + Self::new().left().right() + } + + pub fn up(mut self) -> Self { + self.allow_up = true; + self + } + + pub fn down(mut self) -> Self { + self.allow_down = true; + self + } + + pub fn left(mut self) -> Self { + self.allow_left = true; + self + } + + pub fn right(mut self) -> Self { + self.allow_right = true; + self + } + + fn is_active(&self) -> bool { + self.allow_up || self.allow_down || self.allow_left || self.allow_right + } + + fn ratio(&self, dist: i16) -> f32 { + (dist as f32 / Self::DISTANCE as f32).min(1.0) + } +} + +impl Component for Swipe { + type Msg = SwipeDirection; + + fn place(&mut self, bounds: Rect) -> Rect { + bounds + } + + fn event(&mut self, _ctx: &mut EventCtx, event: Event) -> Option { + if !self.is_active() { + return None; + } + match (event, self.origin) { + (Event::Touch(TouchEvent::TouchStart(pos)), _) => { + // Mark the starting position of this touch. + self.origin.replace(pos); + } + (Event::Touch(TouchEvent::TouchMove(pos)), Some(origin)) => { + // Consider our allowed directions and the touch distance and modify the display + // backlight accordingly. + let ofs = pos - origin; + let abs = ofs.abs(); + if abs.x > abs.y && (self.allow_left || self.allow_right) { + // Horizontal direction. + if (ofs.x < 0 && self.allow_left) || (ofs.x > 0 && self.allow_right) { + // self.backlight(self.ratio(abs.x)); + } + } else if abs.x < abs.y && (self.allow_up || self.allow_down) { + // Vertical direction. + if (ofs.y < 0 && self.allow_up) || (ofs.y > 0 && self.allow_down) { + // self.backlight(self.ratio(abs.y)); + } + }; + } + (Event::Touch(TouchEvent::TouchEnd(pos)), Some(origin)) => { + // Touch interaction is over, reset the position. + self.origin.take(); + + // Compare the touch distance with our allowed directions and determine if it + // constitutes a valid swipe. + let ofs = pos - origin; + let abs = ofs.abs(); + if abs.x > abs.y && (self.allow_left || self.allow_right) { + // Horizontal direction. + if self.ratio(abs.x) >= Self::THRESHOLD { + if ofs.x < 0 && self.allow_left { + return Some(SwipeDirection::Left); + } else if ofs.x > 0 && self.allow_right { + return Some(SwipeDirection::Right); + } + } + } else if abs.x < abs.y && (self.allow_up || self.allow_down) { + // Vertical direction. + if self.ratio(abs.y) >= Self::THRESHOLD { + if ofs.y < 0 && self.allow_up { + return Some(SwipeDirection::Up); + } else if ofs.y > 0 && self.allow_down { + return Some(SwipeDirection::Down); + } + } + }; + } + _ => { + // Do nothing. + } + } + None + } + + fn paint(&mut self) {} + + fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {} +} diff --git a/core/embed/rust/src/ui/component/swipe_detect.rs b/core/embed/rust/src/ui/component/swipe_detect.rs new file mode 100644 index 0000000000..f403d39793 --- /dev/null +++ b/core/embed/rust/src/ui/component/swipe_detect.rs @@ -0,0 +1,401 @@ +use crate::{ + time::{Duration, Instant}, + ui::{ + animation::Animation, + component::{Event, EventCtx, SwipeDirection}, + constant::screen, + event::TouchEvent, + geometry::{Offset, Point}, + util::animation_disabled, + }, +}; + +#[derive(Copy, Clone)] +pub struct SwipeSettings { + pub duration: Duration, +} + +impl SwipeSettings { + pub const fn new(duration: Duration) -> Self { + Self { duration } + } + + pub const fn default() -> Self { + Self { + duration: Duration::from_millis(333), + } + } + + pub const fn immediate() -> Self { + Self { + duration: Duration::from_millis(0), + } + } +} + +#[derive(Copy, Clone, Default)] +pub struct SwipeConfig { + pub horizontal_pages: bool, + pub vertical_pages: bool, + pub up: Option, + pub down: Option, + pub left: Option, + pub right: Option, +} + +impl SwipeConfig { + pub const fn new() -> Self { + Self { + horizontal_pages: false, + vertical_pages: false, + up: None, + down: None, + left: None, + right: None, + } + } + + pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self { + self[dir] = Some(settings); + self + } + + pub fn is_allowed(&self, dir: SwipeDirection) -> bool { + self[dir].is_some() + } + + /// Calculate how much progress over `threshold` was made in the swipe + /// direction. + /// + /// If the swipe direction is not allowed, this will return 0. + pub fn progress(&self, dir: SwipeDirection, movement: Offset, threshold: u16) -> u16 { + if !self.is_allowed(dir) { + return 0; + } + + let correct_movement = match dir { + SwipeDirection::Right => movement.x > 0, + SwipeDirection::Left => movement.x < 0, + SwipeDirection::Down => movement.y > 0, + SwipeDirection::Up => movement.y < 0, + }; + + if !correct_movement { + return 0; + } + + let movement = movement.abs(); + + match dir { + SwipeDirection::Right => (movement.x as u16).saturating_sub(threshold), + SwipeDirection::Left => (movement.x as u16).saturating_sub(threshold), + SwipeDirection::Down => (movement.y as u16).saturating_sub(threshold), + SwipeDirection::Up => (movement.y as u16).saturating_sub(threshold), + } + } + + pub fn duration(&self, dir: SwipeDirection) -> Option { + self[dir].as_ref().map(|s| s.duration) + } + pub fn has_horizontal_pages(&self) -> bool { + self.horizontal_pages + } + + pub fn has_vertical_pages(&self) -> bool { + self.vertical_pages + } + + pub fn with_horizontal_pages(mut self) -> Self { + self.horizontal_pages = true; + self + } + + pub fn with_vertical_pages(mut self) -> Self { + self.vertical_pages = true; + self + } +} + +impl core::ops::Index for SwipeConfig { + type Output = Option; + + fn index(&self, index: SwipeDirection) -> &Self::Output { + match index { + SwipeDirection::Up => &self.up, + SwipeDirection::Down => &self.down, + SwipeDirection::Left => &self.left, + SwipeDirection::Right => &self.right, + } + } +} + +impl core::ops::IndexMut for SwipeConfig { + fn index_mut(&mut self, index: SwipeDirection) -> &mut Self::Output { + match index { + SwipeDirection::Up => &mut self.up, + SwipeDirection::Down => &mut self.down, + SwipeDirection::Left => &mut self.left, + SwipeDirection::Right => &mut self.right, + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum SwipeDetectMsg { + Start(SwipeDirection), + Move(SwipeDirection, u16), + Trigger(SwipeDirection), +} + +pub struct SwipeDetect { + origin: Option, + locked: Option, + final_animation: Option>, + moved: u16, +} + +impl SwipeDetect { + const DISTANCE: u16 = 120; + pub const PROGRESS_MAX: i16 = 1000; + + const DURATION_MS: u32 = 333; + const TRIGGER_THRESHOLD: f32 = 0.3; + const DETECT_THRESHOLD: f32 = 0.1; + + const VERTICAL_PREFERENCE: f32 = 2.0; + + const MIN_LOCK: f32 = Self::DISTANCE as f32 * Self::DETECT_THRESHOLD; + const MIN_TRIGGER: f32 = Self::DISTANCE as f32 * Self::TRIGGER_THRESHOLD; + + pub fn new() -> Self { + Self { + origin: None, + locked: None, + final_animation: None, + moved: 0, + } + } + + fn min_lock(&self, dir: SwipeDirection) -> u16 { + match dir { + SwipeDirection::Up | SwipeDirection::Down => Self::MIN_LOCK as u16, + SwipeDirection::Left | SwipeDirection::Right => { + (Self::MIN_LOCK * Self::VERTICAL_PREFERENCE) as u16 + } + } + } + + fn min_trigger(&self, dir: SwipeDirection) -> u16 { + match dir { + SwipeDirection::Up | SwipeDirection::Down => Self::MIN_TRIGGER as u16, + SwipeDirection::Left | SwipeDirection::Right => { + (Self::MIN_TRIGGER * Self::VERTICAL_PREFERENCE) as u16 + } + } + } + + fn is_lockable(&self, dir: SwipeDirection) -> bool { + let Some(origin) = self.origin else { + return false; + }; + + let min_distance = self.min_trigger(dir) as i16; + + match dir { + SwipeDirection::Up => origin.y > min_distance, + SwipeDirection::Down => origin.y < (screen().height() - min_distance), + SwipeDirection::Left => origin.x > min_distance, + SwipeDirection::Right => origin.x < (screen().width() - min_distance), + } + } + + fn progress(&self, val: u16) -> u16 { + ((val as f32 / Self::DISTANCE as f32) * Self::PROGRESS_MAX as f32) as u16 + } + + fn eval_anim_frame(&mut self, ctx: &mut EventCtx) -> Option { + if let Some(locked) = self.locked { + let mut finish = false; + let res = if let Some(animation) = &self.final_animation { + if animation.finished(Instant::now()) { + finish = true; + if animation.to != 0 { + Some(SwipeDetectMsg::Trigger(locked)) + } else { + Some(SwipeDetectMsg::Move(locked, 0)) + } + } else { + ctx.request_anim_frame(); + ctx.request_paint(); + if animation_disabled() { + None + } else { + Some(SwipeDetectMsg::Move( + locked, + animation.value(Instant::now()).max(0) as u16, + )) + } + } + } else { + None + }; + + if finish { + self.locked = None; + ctx.request_anim_frame(); + ctx.request_paint(); + self.final_animation = None; + self.moved = 0; + } + + return res; + } + None + } + + pub fn trigger(&mut self, ctx: &mut EventCtx, dir: SwipeDirection, config: SwipeConfig) { + ctx.request_anim_frame(); + ctx.request_paint(); + + let duration = config + .duration(dir) + .unwrap_or(Duration::from_millis(Self::DURATION_MS)); + + self.locked = Some(dir); + self.final_animation = Some(Animation::new( + 0, + Self::PROGRESS_MAX, + duration, + Instant::now(), + )); + } + + pub(crate) fn reset(&mut self) { + self.origin = None; + self.locked = None; + self.final_animation = None; + self.moved = 0; + } + + pub(crate) fn event( + &mut self, + ctx: &mut EventCtx, + event: Event, + config: SwipeConfig, + ) -> Option { + match (event, self.origin) { + (Event::Touch(TouchEvent::TouchStart(pos)), _) => { + if self.final_animation.is_none() { + // Mark the starting position of this touch. + self.origin.replace(pos); + } else { + return self.eval_anim_frame(ctx); + } + } + (Event::Touch(TouchEvent::TouchMove(pos)), Some(origin)) => { + if self.final_animation.is_none() { + // Compare the touch distance with our allowed directions and determine if it + // constitutes a valid swipe. + let ofs = pos - origin; + + let res = match self.locked { + Some(locked) => { + // advance in locked direction only + let moved = config.progress(locked, ofs, self.min_lock(locked)); + Some(SwipeDetectMsg::Move(locked, self.progress(moved))) + } + None => { + let mut res = None; + for dir in SwipeDirection::iter() { + let progress = config.progress(dir, ofs, self.min_lock(dir)); + if progress > 0 && self.is_lockable(dir) { + self.locked = Some(dir); + res = Some(SwipeDetectMsg::Start(dir)); + break; + } + } + res + } + }; + + if let Some(SwipeDetectMsg::Move(_, progress)) = res { + self.moved = progress; + } + + if animation_disabled() { + return None; + } + + return res; + } else { + return self.eval_anim_frame(ctx); + } + } + (Event::Touch(TouchEvent::TouchEnd(pos)), Some(origin)) => { + if self.final_animation.is_none() { + // Touch interaction is over, reset the position. + self.origin.take(); + + // Compare the touch distance with our allowed directions and determine if it + // constitutes a valid swipe. + let ofs = pos - origin; + + let final_value = match self.locked { + // advance in locked direction only trigger animation towards ending + // position + Some(locked) + if config.progress(locked, ofs, self.min_trigger(locked)) > 0 => + { + Self::PROGRESS_MAX + } + // advance in direction other than locked trigger animation towards starting + // position + Some(_) => 0, + None => return None, + }; + + let Some(locked) = self.locked else { + // Touch ended without triggering a swipe. + return None; + }; + + ctx.request_anim_frame(); + ctx.request_paint(); + + if !animation_disabled() { + let done = self.moved as f32 / Self::PROGRESS_MAX as f32; + let ratio = if final_value == 0 { done } else { 1.0 - done }; + + let duration = config + .duration(locked) + .unwrap_or(Duration::from_millis(Self::DURATION_MS)); + + let duration = ((duration.to_millis() as f32 * ratio) as u32).max(0); + self.final_animation = Some(Animation::new( + self.moved as i16, + final_value, + Duration::from_millis(duration), + Instant::now(), + )); + } else { + // clear animation + self.final_animation = None; + self.moved = 0; + self.locked = None; + return Some(SwipeDetectMsg::Trigger(locked)); + } + return None; + } else { + return self.eval_anim_frame(ctx); + } + } + (Event::Timer(EventCtx::ANIM_FRAME_TIMER), _) => { + return self.eval_anim_frame(ctx); + } + _ => { + // Do nothing. + } + } + None + } +} diff --git a/core/embed/rust/src/ui/component/text/common.rs b/core/embed/rust/src/ui/component/text/common.rs index 82d66e16c3..34d5015cd5 100644 --- a/core/embed/rust/src/ui/component/text/common.rs +++ b/core/embed/rust/src/ui/component/text/common.rs @@ -1,5 +1,7 @@ -use crate::ui::{component::EventCtx, util::ResultExt}; -use heapless::String; +use crate::{ + strutil::ShortString, + ui::{component::EventCtx, util::ResultExt}, +}; /// Reified editing operations of `TextBox`. /// @@ -13,19 +15,21 @@ pub enum TextEdit { /// Wraps a character buffer of maximum length `L` and provides text editing /// operations over it. Text ops usually take a `EventCtx` to request a paint /// pass in case of any state modification. -pub struct TextBox { - text: String, +pub struct TextBox { + text: ShortString, } -impl TextBox { +impl TextBox { /// Create a new `TextBox` with content `text`. - pub fn new(text: String) -> Self { + pub fn new(text: &str, max_len: usize) -> Self { + let text = unwrap!(ShortString::try_from(text)); + debug_assert!(text.capacity() >= max_len); Self { text } } /// Create an empty `TextBox`. - pub fn empty() -> Self { - Self::new(String::new()) + pub fn empty(max_len: usize) -> Self { + Self::new("", max_len) } pub fn content(&self) -> &str { @@ -40,10 +44,6 @@ impl TextBox { self.text.is_empty() } - pub fn is_full(&self) -> bool { - self.text.len() == self.text.capacity() - } - /// Delete the last character of content, if any. pub fn delete_last(&mut self, ctx: &mut EventCtx) { let changed = self.text.pop().is_some(); @@ -107,7 +107,7 @@ impl TextBox { // DEBUG-ONLY SECTION BELOW #[cfg(feature = "ui_debug")] -impl crate::trace::Trace for TextBox { +impl crate::trace::Trace for TextBox { fn trace(&self, t: &mut dyn crate::trace::Tracer) { t.component("TextBox"); t.string("text", self.text.as_str().into()); diff --git a/core/embed/rust/src/ui/component/text/formatted.rs b/core/embed/rust/src/ui/component/text/formatted.rs index 48d97811e8..9219dbdcb8 100644 --- a/core/embed/rust/src/ui/component/text/formatted.rs +++ b/core/embed/rust/src/ui/component/text/formatted.rs @@ -1,10 +1,11 @@ use crate::ui::{ component::{Component, Event, EventCtx, Never, Paginate}, geometry::{Alignment, Offset, Rect}, + shape::Renderer, }; use super::{ - layout::{LayoutFit, LayoutSink, TextNoOp, TextRenderer}, + layout::{LayoutFit, LayoutSink, TextNoOp, TextRenderer, TextRenderer2}, op::OpTextLayout, }; @@ -133,9 +134,8 @@ impl Component for FormattedText { self.layout_content(&mut TextRenderer); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.op_layout.layout.bounds) + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.layout_content(&mut TextRenderer2::new(target)); } } @@ -155,3 +155,13 @@ impl crate::trace::Trace for FormattedText { t.bool("fits", matches!(fit.get(), Some(LayoutFit::Fitting { .. }))); } } + +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl ComponentMsgObj for super::FormattedText { + fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { + unreachable!(); + } + } +} diff --git a/core/embed/rust/src/ui/component/text/layout.rs b/core/embed/rust/src/ui/component/text/layout.rs index 5c86089dfc..52a422ba58 100644 --- a/core/embed/rust/src/ui/component/text/layout.rs +++ b/core/embed/rust/src/ui/component/text/layout.rs @@ -2,6 +2,8 @@ use crate::ui::{ display, display::{toif::Icon, Color, Font, GlyphMetrics}, geometry::{Alignment, Alignment2D, Dimensions, Offset, Point, Rect}, + shape, + shape::Renderer, }; const ELLIPSIS: &str = "..."; @@ -197,7 +199,7 @@ impl TextStyle { impl TextLayout { /// Create a new text layout, with empty size and default text parameters /// filled from `T`. - pub fn new(style: TextStyle) -> Self { + pub const fn new(style: TextStyle) -> Self { Self { bounds: Rect::zero(), padding_top: 0, @@ -208,12 +210,12 @@ impl TextLayout { } } - pub fn with_bounds(mut self, bounds: Rect) -> Self { + pub const fn with_bounds(mut self, bounds: Rect) -> Self { self.bounds = bounds; self } - pub fn with_align(mut self, align: Alignment) -> Self { + pub const fn with_align(mut self, align: Alignment) -> Self { self.align = align; self } @@ -235,6 +237,24 @@ impl TextLayout { self.layout_text(text, &mut self.initial_cursor(), &mut TextRenderer) } + /// Draw as much text as possible on the current screen. + pub fn render_text2<'s>(&self, text: &str, target: &mut impl Renderer<'s>) -> LayoutFit { + self.render_text_with_alpha(text, target, 255) + } + /// Draw as much text as possible on the current screen. + pub fn render_text_with_alpha<'s>( + &self, + text: &str, + target: &mut impl Renderer<'s>, + alpha: u8, + ) -> LayoutFit { + self.layout_text( + text, + &mut self.initial_cursor(), + &mut TextRenderer2::new(target).with_alpha(alpha), + ) + } + /// Loop through the `text` and try to fit it on the current screen, /// reporting events to `sink`, which may do something with them (e.g. draw /// on screen). @@ -530,6 +550,86 @@ impl LayoutSink for TextRenderer { } } +pub struct TextRenderer2<'a, 's, R> +where + R: Renderer<'s>, +{ + pub renderer: &'a mut R, + pd: core::marker::PhantomData<&'s ()>, + alpha: u8, +} + +impl<'a, 's, R> TextRenderer2<'a, 's, R> +where + R: Renderer<'s>, +{ + pub fn new(target: &'a mut R) -> Self { + Self { + renderer: target, + pd: core::marker::PhantomData, + alpha: 255, + } + } + + pub fn with_alpha(self, alpha: u8) -> Self { + Self { alpha, ..self } + } +} + +impl<'a, 's, R> LayoutSink for TextRenderer2<'a, 's, R> +where + R: Renderer<'s>, +{ + fn text(&mut self, cursor: Point, layout: &TextLayout, text: &str) { + shape::Text::new(cursor, text) + .with_font(layout.style.text_font) + .with_fg(layout.style.text_color) + .with_alpha(self.alpha) + .render(self.renderer); + } + + fn hyphen(&mut self, cursor: Point, layout: &TextLayout) { + shape::Text::new(cursor, "-") + .with_font(layout.style.text_font) + .with_fg(layout.style.hyphen_color) + .with_alpha(self.alpha) + .render(self.renderer); + } + + fn ellipsis(&mut self, cursor: Point, layout: &TextLayout) { + if let Some((icon, margin)) = layout.style.ellipsis_icon { + let bottom_left = cursor + Offset::x(margin); + shape::ToifImage::new(bottom_left, icon.toif) + .with_align(Alignment2D::BOTTOM_LEFT) + .with_fg(layout.style.ellipsis_color) + .with_alpha(self.alpha) + .render(self.renderer); + } else { + shape::Text::new(cursor, ELLIPSIS) + .with_font(layout.style.text_font) + .with_fg(layout.style.ellipsis_color) + .with_alpha(self.alpha) + .render(self.renderer); + } + } + + fn prev_page_ellipsis(&mut self, cursor: Point, layout: &TextLayout) { + if let Some((icon, _margin)) = layout.style.prev_page_ellipsis_icon { + shape::ToifImage::new(cursor, icon.toif) + .with_align(Alignment2D::BOTTOM_LEFT) + .with_fg(layout.style.ellipsis_color) + .with_alpha(self.alpha) + .render(self.renderer); + } else { + shape::Text::new(cursor, ELLIPSIS) + .with_font(layout.style.text_font) + .with_fg(layout.style.ellipsis_color) + .with_alpha(self.alpha) + .render(self.renderer); + } + } +} + #[cfg(feature = "ui_debug")] pub mod trace { use crate::{trace::ListTracer, ui::geometry::Point}; diff --git a/core/embed/rust/src/ui/component/text/op.rs b/core/embed/rust/src/ui/component/text/op.rs index 6e4d11413f..101bfc8c22 100644 --- a/core/embed/rust/src/ui/component/text/op.rs +++ b/core/embed/rust/src/ui/component/text/op.rs @@ -253,6 +253,10 @@ impl<'a> OpTextLayout<'a> { self.font(Font::BOLD).text(text.into()) } + pub fn text_bold_upper(self, text: impl Into>) -> Self { + self.font(Font::BOLD_UPPER).text(text.into()) + } + pub fn text_demibold(self, text: impl Into>) -> Self { self.font(Font::DEMIBOLD).text(text.into()) } diff --git a/core/embed/rust/src/ui/component/text/paragraphs.rs b/core/embed/rust/src/ui/component/text/paragraphs.rs index 1fd658c134..e2674caf72 100644 --- a/core/embed/rust/src/ui/component/text/paragraphs.rs +++ b/core/embed/rust/src/ui/component/text/paragraphs.rs @@ -4,10 +4,12 @@ use crate::{ strutil::TString, ui::{ component::{Component, Event, EventCtx, Never, Paginate}, - display::toif::Icon, + display::{toif::Icon, Color, Font}, geometry::{ Alignment, Alignment2D, Dimensions, Insets, LinearPlacement, Offset, Point, Rect, }, + shape, + shape::Renderer, }, }; @@ -45,6 +47,7 @@ pub trait ParagraphSource<'a> { } } +#[derive(Clone)] pub struct Paragraphs { area: Rect, placement: LinearPlacement, @@ -87,6 +90,19 @@ where &mut self.source } + pub fn area(&self) -> Rect { + let mut result: Option = None; + Self::foreach_visible( + &self.source, + &self.visible, + self.offset, + &mut |layout, _content| { + result = result.map_or(Some(layout.bounds), |r| Some(r.union(layout.bounds))); + }, + ); + result.unwrap_or(self.area) + } + /// Update bounding boxes of paragraphs on the current page. First determine /// the number of visible paragraphs and their sizes. These are then /// arranged according to the layout. @@ -185,12 +201,15 @@ where ) } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.area); - for layout in &self.visible { - sink(layout.bounds) - } + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + Self::foreach_visible( + &self.source, + &self.visible, + self.offset, + &mut |layout, content| { + layout.render_text2(content, target); + }, + ) } } @@ -322,6 +341,7 @@ impl<'a> Paragraph<'a> { } } +#[derive(Clone)] struct TextLayoutProxy { offset: PageOffset, bounds: Rect, @@ -542,6 +562,8 @@ pub struct Checklist { current: usize, icon_current: Icon, icon_done: Icon, + icon_done_color: Option, + show_numerals: bool, /// How wide will the left icon column be check_width: i16, /// Offset of the icon representing DONE @@ -550,7 +572,10 @@ pub struct Checklist { current_offset: Offset, } -impl Checklist { +impl<'a, T> Checklist +where + T: ParagraphSource<'a>, +{ pub fn from_paragraphs( icon_current: Icon, icon_done: Icon, @@ -563,6 +588,8 @@ impl Checklist { current, icon_current, icon_done, + icon_done_color: None, + show_numerals: false, check_width: 0, done_offset: Offset::zero(), current_offset: Offset::zero(), @@ -584,6 +611,38 @@ impl Checklist { self } + pub fn with_icon_done_color(mut self, col: Color) -> Self { + self.icon_done_color = Some(col); + self + } + + pub fn with_numerals(mut self) -> Self { + self.show_numerals = true; + self + } + + fn render_left_column<'s>(&self, target: &mut impl Renderer<'s>) { + let current_visible = self.current.saturating_sub(self.paragraphs.offset.par); + for (i, layout) in self.paragraphs.visible.iter().enumerate() { + let l = &layout.layout(&self.paragraphs.source); + let base = Point::new(self.area.x0, l.bounds.y0); + if i < current_visible { + // finished tasks - labeled with icon "done" + let color = self.icon_done_color.unwrap_or(l.style.text_color); + self.render_icon(base + self.done_offset, self.icon_done, color, target) + } else { + // current and future tasks - ordinal numbers or icon on current task + if self.show_numerals { + let num_offset = Offset::new(4, Font::NORMAL.visible_text_height("1")); + self.render_numeral(base + num_offset, i, l.style.text_color, target); + } else if i == current_visible { + let color = l.style.text_color; + self.render_icon(base + self.current_offset, self.icon_current, color, target); + } + } + } + } + fn paint_icon(&self, layout: &TextLayout, icon: Icon, offset: Offset) { let top_left = Point::new(self.area.x0, layout.bounds.y0); icon.draw( @@ -593,6 +652,32 @@ impl Checklist { layout.style.background_color, ); } + + fn render_numeral<'s>( + &self, + base_point: Point, + n: usize, + color: Color, + target: &mut impl Renderer<'s>, + ) { + let numeral = uformat!("{}.", n + 1); + shape::Text::new(base_point, numeral.as_str()) + .with_font(Font::SUB) + .with_fg(color) + .render(target); + } + + fn render_icon<'s>( + &self, + base_point: Point, + icon: Icon, + color: Color, + target: &mut impl Renderer<'s>, + ) { + shape::ToifImage::new(base_point, icon.toif) + .with_fg(color) + .render(target); + } } impl<'a, T> Component for Checklist @@ -632,10 +717,9 @@ where } } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.area); - self.paragraphs.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.paragraphs.render(target); + self.render_left_column(target); } } @@ -659,6 +743,16 @@ impl<'a, T: ParagraphSource<'a>> crate::trace::Trace for Checklist { } } +#[cfg(feature = "micropython")] +mod micropython { + use crate::{error::Error, micropython::obj::Obj, ui::layout::obj::ComponentMsgObj}; + impl<'a, T: super::ParagraphSource<'a>> ComponentMsgObj for super::Checklist { + fn msg_try_into_obj(&self, _msg: Self::Msg) -> Result { + unreachable!(); + } + } +} + pub trait VecExt<'a> { fn add(&mut self, paragraph: Paragraph<'a>) -> &mut Self; } @@ -670,7 +764,7 @@ impl<'a, const N: usize> VecExt<'a> for Vec, N> { } if self.push(paragraph).is_err() { #[cfg(feature = "ui_debug")] - panic!("paragraph list is full"); + fatal_error!("Paragraph list is full"); } self } diff --git a/core/embed/rust/src/ui/component/text/util.rs b/core/embed/rust/src/ui/component/text/util.rs index b417539caf..69ddd4de42 100644 --- a/core/embed/rust/src/ui/component/text/util.rs +++ b/core/embed/rust/src/ui/component/text/util.rs @@ -3,6 +3,7 @@ use crate::{ ui::{ display::{Color, Font}, geometry::{Alignment, Rect}, + shape::Renderer, }, }; @@ -37,6 +38,33 @@ pub fn text_multiline( } } +/// Draws longer multiline texts inside an area. +/// Splits lines on word boundaries/whitespace. +/// When a word is too long to fit one line, splitting +/// it on multiple lines with "-" at the line-ends. +/// +/// If it fits, returns the rest of the area. +/// If it does not fit, returns `None`. +pub fn text_multiline2<'s>( + target: &mut impl Renderer<'s>, + area: Rect, + text: TString<'_>, + font: Font, + fg_color: Color, + bg_color: Color, + alignment: Alignment, +) -> Option { + let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color); + let text_layout = TextLayout::new(text_style) + .with_bounds(area) + .with_align(alignment); + let layout_fit = text.map(|t| text_layout.render_text2(t, target)); + match layout_fit { + LayoutFit::Fitting { height, .. } => Some(area.split_top(height).1), + LayoutFit::OutOfBounds { .. } => None, + } +} + /// Same as `text_multiline` above, but aligns the text to the bottom of the /// area. pub fn text_multiline_bottom( @@ -66,3 +94,34 @@ pub fn text_multiline_bottom( } }) } + +/// Same as `text_multiline` above, but aligns the text to the bottom of the +/// area. +pub fn text_multiline_bottom2<'s>( + target: &mut impl Renderer<'s>, + area: Rect, + text: TString<'_>, + font: Font, + fg_color: Color, + bg_color: Color, + alignment: Alignment, +) -> Option { + let text_style = TextStyle::new(font, fg_color, bg_color, fg_color, fg_color); + let mut text_layout = TextLayout::new(text_style) + .with_bounds(area) + .with_align(alignment); + // When text fits the area, displaying it in the bottom part. + // When not, render it "normally". + text.map(|t| match text_layout.fit_text(t) { + LayoutFit::Fitting { height, .. } => { + let (top, bottom) = area.split_bottom(height); + text_layout = text_layout.with_bounds(bottom); + text_layout.render_text2(t, target); + Some(top) + } + LayoutFit::OutOfBounds { .. } => { + text_layout.render_text2(t, target); + None + } + }) +} diff --git a/core/embed/rust/src/ui/component/timeout.rs b/core/embed/rust/src/ui/component/timeout.rs index 67d29c7504..bd0466c109 100644 --- a/core/embed/rust/src/ui/component/timeout.rs +++ b/core/embed/rust/src/ui/component/timeout.rs @@ -3,9 +3,11 @@ use crate::{ ui::{ component::{Component, Event, EventCtx, TimerToken}, geometry::Rect, + shape::Renderer, }, }; +#[derive(Clone)] pub struct Timeout { time_ms: u32, timer: Option, @@ -30,7 +32,7 @@ impl Component for Timeout { fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { match event { // Set up timer. - Event::Attach => { + Event::Attach(_) => { self.timer = Some(ctx.request_timer(Duration::from_millis(self.time_ms))); None } @@ -44,6 +46,8 @@ impl Component for Timeout { } fn paint(&mut self) {} + + fn render<'s>(&'s self, _target: &mut impl Renderer<'s>) {} } #[cfg(feature = "ui_debug")] diff --git a/core/embed/rust/src/ui/display/color.rs b/core/embed/rust/src/ui/display/color.rs index 945eba3ee8..0bf42bf15f 100644 --- a/core/embed/rust/src/ui/display/color.rs +++ b/core/embed/rust/src/ui/display/color.rs @@ -1,12 +1,31 @@ use crate::ui::lerp::Lerp; +#[cfg(not(feature = "ui_color_32bit"))] #[derive(Copy, Clone, PartialEq, Eq)] pub struct Color(u16); +#[cfg(feature = "ui_color_32bit")] +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct Color { + r: u8, + g: u8, + b: u8, +} impl Color { + #[cfg(not(feature = "ui_color_32bit"))] pub const fn from_u16(val: u16) -> Self { Self(val) } + + #[cfg(feature = "ui_color_32bit")] + pub const fn from_u16(val: u16) -> Self { + Self { + r: ((((val) & 0xF800) >> 8) | (((val) & 0xF800) >> 13)) as u8, + g: ((((val) & 0x07E0) >> 3) | (((val) & 0x07E0) >> 9)) as u8, + b: ((((val) & 0x001F) << 3) | (((val) & 0x001F) >> 2)) as u8, + } + } + pub const fn from_u32(val: u32) -> Self { Self::rgb( ((val >> 16) & 0xFF) as u8, @@ -15,12 +34,17 @@ impl Color { ) } + #[cfg(not(feature = "ui_color_32bit"))] pub const fn rgb(r: u8, g: u8, b: u8) -> Self { let r = (r as u16 & 0xF8) << 8; let g = (g as u16 & 0xFC) << 3; let b = (b as u16 & 0xF8) >> 3; Self(r | g | b) } + #[cfg(feature = "ui_color_32bit")] + pub const fn rgb(r: u8, g: u8, b: u8) -> Self { + Self { r, g, b } + } pub const fn luminance(self) -> u32 { (self.r() as u32 * 299) / 1000 @@ -33,36 +57,56 @@ impl Color { let g_u16 = g as u16; let b_u16 = b as u16; - let r = ((256 - alpha) * bg.r() as u16 + alpha * r_u16) >> 8; - let g = ((256 - alpha) * bg.g() as u16 + alpha * g_u16) >> 8; - let b = ((256 - alpha) * bg.b() as u16 + alpha * b_u16) >> 8; + let r = (((256 - alpha) * bg.r() as u16 + alpha * r_u16) >> 8) as u8; + let g = (((256 - alpha) * bg.g() as u16 + alpha * g_u16) >> 8) as u8; + let b = (((256 - alpha) * bg.b() as u16 + alpha * b_u16) >> 8) as u8; - let r = (r & 0xF8) << 8; - let g = (g & 0xFC) << 3; - let b = (b & 0xF8) >> 3; - Self(r | g | b) + Self::rgb(r, g, b) } pub const fn alpha(bg: Color, alpha: u16) -> Self { Self::rgba(bg, 0xFF, 0xFF, 0xFF, alpha) } + #[cfg(not(feature = "ui_color_32bit"))] pub const fn r(self) -> u8 { (self.0 >> 8) as u8 & 0xF8 } + #[cfg(not(feature = "ui_color_32bit"))] pub const fn g(self) -> u8 { (self.0 >> 3) as u8 & 0xFC } + #[cfg(not(feature = "ui_color_32bit"))] pub const fn b(self) -> u8 { (self.0 << 3) as u8 & 0xF8 } + #[cfg(feature = "ui_color_32bit")] + pub const fn r(self) -> u8 { + self.r + } + #[cfg(feature = "ui_color_32bit")] + pub const fn g(self) -> u8 { + self.g + } + #[cfg(feature = "ui_color_32bit")] + pub const fn b(self) -> u8 { + self.b + } + #[cfg(not(feature = "ui_color_32bit"))] pub fn to_u16(self) -> u16 { self.0 } + #[cfg(feature = "ui_color_32bit")] + pub fn to_u16(self) -> u16 { + (((self.r() & 0xF8) as u16) << 8) + | (((self.g() & 0xFC) as u16) << 3) + | ((self.b() & 0xF8) as u16 >> 3) + } + pub fn to_u32(self) -> u32 { ((self.r() as u32) << 16) | ((self.g() as u32) << 8) | (self.b() as u32) | 0xff000000 } @@ -75,10 +119,20 @@ impl Color { (self.to_u16() & 0xFF) as u8 } + #[cfg(not(feature = "ui_color_32bit"))] pub fn negate(self) -> Self { Self(!self.0) } + #[cfg(feature = "ui_color_32bit")] + pub fn negate(self) -> Self { + Self { + r: 255 - self.r, + g: 255 - self.g, + b: 255 - self.b, + } + } + pub const fn white() -> Self { Self::rgb(255, 255, 255) } @@ -98,7 +152,7 @@ impl Color { let r = (fg.r() as u16) * fg_mul + (self.r() as u16) * bg_mul; let g = (fg.g() as u16) * fg_mul + (self.g() as u16) * bg_mul; let b = (fg.b() as u16) * fg_mul + (self.b() as u16) * bg_mul; - Color::rgb((r >> 8) as u8, (g >> 8) as u8, (b >> 8) as u8) + Color::rgb((r / 255) as u8, (g / 255) as u8, (b / 255) as u8) } } @@ -113,7 +167,7 @@ impl Lerp for Color { impl From for Color { fn from(val: u16) -> Self { - Self(val) + Self::from_u16(val) } } diff --git a/core/embed/rust/src/ui/display/font.rs b/core/embed/rust/src/ui/display/font.rs index b88953b98a..fd410a43bf 100644 --- a/core/embed/rust/src/ui/display/font.rs +++ b/core/embed/rust/src/ui/display/font.rs @@ -3,6 +3,7 @@ use crate::{ ui::{ constant, geometry::{Offset, Point, Rect}, + shape::{Bitmap, BitmapFormat}, }, }; use core::slice; @@ -41,12 +42,12 @@ impl Glyph { let width = *data.offset(0) as i16; let height = *data.offset(1) as i16; - let data_bits = constant::FONT_BPP * width * height; - - let data_bytes = if data_bits % 8 == 0 { - data_bits / 8 - } else { - (data_bits / 8) + 1 + let data_bytes = match constant::FONT_BPP { + 1 => (width * height + 7) / 8, // packed bits + 2 => (width * height + 3) / 4, // packed bits + 4 => (width + 1) / 2 * height, // row aligned to bytes + 8 => width * height, + _ => fatal_error!("Unsupported font bpp"), }; Glyph { @@ -119,18 +120,42 @@ impl Glyph { _ => 0, } } + + pub fn bitmap(&self) -> Bitmap<'static> { + match constant::FONT_BPP { + 1 => unwrap!(Bitmap::new( + BitmapFormat::MONO1P, + None, + Offset::new(self.width, self.height), + None, + self.data, + )), + 4 => unwrap!(Bitmap::new( + BitmapFormat::MONO4, + None, + Offset::new(self.width, self.height), + None, + self.data, + )), + _ => unimplemented!(), + } + } } /// Font constants. Keep in sync with FONT_ definitions in -/// `extmod/modtrezorui/fonts/fonts.h`. +/// `core/embed/lib/fonts/fonts.h`. #[derive(Copy, Clone, PartialEq, Eq, FromPrimitive)] #[repr(u8)] +#[allow(non_camel_case_types)] pub enum Font { NORMAL = 1, BOLD = 2, MONO = 3, BIG = 4, DEMIBOLD = 5, + NORMAL_UPPER = 6, + BOLD_UPPER = 7, + SUB = 8, } impl From for i32 { @@ -240,7 +265,32 @@ impl Font { constant::LINE_SPACE + self.text_height() } + /// Helper functions for **horizontal** text centering. + /// + /// The `text` is centered between `start` and `end`. + /// + /// Returns x-coordinate of the centered text start (including left + /// bearing). + pub fn horz_center(&self, start: i16, end: i16, text: &str) -> i16 { + (start + end - self.visible_text_width(text)) / 2 - self.start_x_bearing(text) + } + + /// Helper functions for **vertical** text centering. + /// + /// The `text` is centered between `start` and `end`. + /// + /// Returns y-coordinate of the centered text baseline. + pub fn vert_center(&self, start: i16, end: i16, text: &str) -> i16 { + (start + end + self.visible_text_height(text)) / 2 + } + pub fn get_glyph(self, ch: char) -> Glyph { + /* have the non-breaking space counted for width but not counted as a + * breaking point */ + let ch = match ch { + '\u{00a0}' => '\u{0020}', + c => c, + }; let gl_data = display::get_char_glyph(ch as u16, self.into()); ensure!(!gl_data.is_null(), "Failed to load glyph"); @@ -273,6 +323,16 @@ impl Font { text.len() // it fits in its entirety } + + pub fn visible_text_height_ex(&self, text: &str) -> (i16, i16) { + let (mut ascent, mut descent) = (0, 0); + for c in text.chars() { + let glyph = self.get_glyph(c); + ascent = ascent.max(glyph.bearing_y); + descent = descent.max(glyph.height - glyph.bearing_y); + } + (ascent, descent) + } } pub trait GlyphMetrics { diff --git a/core/embed/rust/src/ui/display/image.rs b/core/embed/rust/src/ui/display/image.rs new file mode 100644 index 0000000000..cbca9339d5 --- /dev/null +++ b/core/embed/rust/src/ui/display/image.rs @@ -0,0 +1,225 @@ +use crate::{io::BinaryData, ui::geometry::Offset}; + +impl<'a> BinaryData<'a> { + fn read_u8(&self, ofs: usize) -> Option { + let mut buff: [u8; 1] = [0; 1]; + if self.read(ofs, buff.as_mut()) == buff.len() { + Some(buff[0]) + } else { + None + } + } + + fn read_u16_le(&self, ofs: usize) -> Option { + let mut buff: [u8; 2] = [0; 2]; + if self.read(ofs, buff.as_mut()) == buff.len() { + Some(u16::from_le_bytes(buff)) + } else { + None + } + } + + fn read_u16_be(&self, ofs: usize) -> Option { + let mut buff: [u8; 2] = [0; 2]; + if self.read(ofs, buff.as_mut()) == buff.len() { + Some(u16::from_be_bytes(buff)) + } else { + None + } + } + + fn read_u32_le(&self, ofs: usize) -> Option { + let mut buff: [u8; 4] = [0; 4]; + if self.read(ofs, buff.as_mut()) == buff.len() { + Some(u32::from_le_bytes(buff)) + } else { + None + } + } +} + +#[derive(PartialEq, Debug, Eq, FromPrimitive, Clone, Copy)] +pub enum ToifFormat { + FullColorBE = 0, // big endian + GrayScaleOH = 1, // odd hi + FullColorLE = 2, // little endian + GrayScaleEH = 3, // even hi +} + +pub struct ToifInfo { + format: ToifFormat, + size: Offset, + len: usize, +} + +impl ToifInfo { + pub const HEADER_LENGTH: usize = 12; + + pub fn parse(image: BinaryData) -> Option { + if image.read_u8(0)? != b'T' && image.read_u8(1)? != b'O' && image.read_u8(2)? != b'I' { + return None; + } + + let format = match image.read_u8(3)? { + b'f' => ToifFormat::FullColorBE, + b'g' => ToifFormat::GrayScaleOH, + b'F' => ToifFormat::FullColorLE, + b'G' => ToifFormat::GrayScaleEH, + _ => return None, + }; + + let width = image.read_u16_le(4)?; + let height = image.read_u16_le(6)?; + let len = image.read_u32_le(8)? as usize; + + if width > 1024 || height > 1024 || len > 65536 { + return None; + } + + if len + Self::HEADER_LENGTH != image.len() { + return None; + } + + Some(Self { + format, + size: Offset::new(width as i16, height as i16), + len, + }) + } + + pub fn format(&self) -> ToifFormat { + self.format + } + + pub fn size(&self) -> Offset { + self.size + } + + pub fn width(&self) -> i16 { + self.size.x + } + + pub fn height(&self) -> i16 { + self.size.y + } + + pub fn is_grayscale(&self) -> bool { + matches!( + self.format, + ToifFormat::GrayScaleOH | ToifFormat::GrayScaleEH + ) + } + + pub fn stride(&self) -> usize { + if self.is_grayscale() { + (self.width() + 1) as usize / 2 + } else { + self.width() as usize * 2 + } + } +} + +pub struct JpegInfo { + size: Offset, + mcu_height: i16, +} + +impl JpegInfo { + pub fn parse(image: BinaryData) -> Option { + const M_SOI: u16 = 0xFFD8; + const M_SOF0: u16 = 0xFFC0; + const M_DRI: u16 = 0xFFDD; + const M_RST0: u16 = 0xFFD0; + const M_RST7: u16 = 0xFFD7; + const M_SOS: u16 = 0xFFDA; + const M_EOI: u16 = 0xFFD9; + + let mut result = None; + let mut ofs = 0; + + while image.read_u16_be(ofs)? != M_SOI { + ofs += 1; + } + + loop { + let marker = image.read_u16_be(ofs)?; + + if (marker & 0xFF00) != 0xFF00 { + return None; + } + + ofs += 2; + + ofs += match marker { + M_SOI => 0, + M_SOF0 => { + let w = image.read_u16_be(ofs + 3)? as i16; + let h = image.read_u16_be(ofs + 5)? as i16; + // Number of components + let nc = image.read_u8(ofs + 7)?; + if (nc != 1) && (nc != 3) { + return None; + } + // Sampling factor of the first component + let c1 = image.read_u8(ofs + 9)?; + if (c1 != 0x11) && (c1 != 0x21) & (c1 != 0x22) { + return None; + }; + let mcu_height = (8 * (c1 & 15)) as i16; + + // We now have all the information we need, but + // we will not exit the loop yet until we find the + // M_SOS marker. While this does not ensure absolute + // correctness, it improves the verification slightly. + result = Some(JpegInfo { + size: Offset::new(w, h), + mcu_height, + }); + + image.read_u16_be(ofs)? + } + M_DRI => 4, + M_EOI => return None, + M_RST0..=M_RST7 => 0, + M_SOS => break, + _ => image.read_u16_be(ofs)?, + } as usize; + } + + result + } + + pub fn size(&self) -> Offset { + self.size + } + + pub fn width(&self) -> i16 { + self.size.x + } + + pub fn height(&self) -> i16 { + self.size.y + } + + pub fn mcu_height(&self) -> i16 { + self.mcu_height + } +} + +pub enum ImageInfo { + Invalid, + Toif(ToifInfo), + Jpeg(JpegInfo), +} + +impl ImageInfo { + pub fn parse(image: BinaryData) -> Self { + if let Some(info) = ToifInfo::parse(image) { + Self::Toif(info) + } else if let Some(info) = JpegInfo::parse(image) { + Self::Jpeg(info) + } else { + Self::Invalid + } + } +} diff --git a/core/embed/rust/src/ui/display/mod.rs b/core/embed/rust/src/ui/display/mod.rs index 4ee411e887..390c977eff 100644 --- a/core/embed/rust/src/ui/display/mod.rs +++ b/core/embed/rust/src/ui/display/mod.rs @@ -1,5 +1,6 @@ pub mod color; pub mod font; +pub mod image; pub mod loader; #[cfg(feature = "jpeg")] pub mod tjpgd; @@ -48,44 +49,44 @@ use crate::trezorhal::{ }; use crate::ui::constant::WIDTH; -pub fn backlight() -> u16 { - display::backlight(-1) as u16 +pub fn backlight() -> u8 { + display::backlight(-1) as u8 } #[cfg(feature = "backlight")] -pub fn set_backlight(val: u16) { +pub fn set_backlight(val: u8) { display::backlight(val as i32); } #[cfg(feature = "backlight")] -pub fn fade_backlight(target: u16) { +pub fn fade_backlight(target: u8) { const FADE_DURATION_MS: u32 = 50; fade_backlight_duration(target, FADE_DURATION_MS); } #[cfg(feature = "backlight")] -pub fn fade_backlight_duration(target: u16, duration_ms: u32) { +pub fn fade_backlight_duration(target: u8, duration_ms: u32) { let target = target as i32; let duration_ms = duration_ms as i32; let current = backlight() as i32; for i in 0..duration_ms { let val = i32::lerp(current, target, i as f32 / duration_ms as f32); - set_backlight(val as u16); + set_backlight(val as u8); time::sleep(Duration::from_millis(1)); } //account for imprecise rounding - set_backlight(target as u16); + set_backlight(target as u8); } #[cfg(not(feature = "backlight"))] -pub fn set_backlight(_: u16) {} +pub fn set_backlight(_: u8) {} #[cfg(not(feature = "backlight"))] -pub fn fade_backlight(_: u16) {} +pub fn fade_backlight(_: u8) {} #[cfg(not(feature = "backlight"))] -pub fn fade_backlight_duration(_: u16, _: u32) {} +pub fn fade_backlight_duration(_: u8, _: u32) {} #[cfg(not(feature = "framebuffer"))] /// Fill a whole rectangle with a specific color. diff --git a/core/embed/rust/src/ui/display/tjpgd.rs b/core/embed/rust/src/ui/display/tjpgd.rs index 1fc6de3455..734cad50c9 100644 --- a/core/embed/rust/src/ui/display/tjpgd.rs +++ b/core/embed/rust/src/ui/display/tjpgd.rs @@ -20,7 +20,7 @@ pub fn jpeg(data: &[u8], pos: Point, scale: u8) { let mut inp = BufferInput(data); if let Ok(mut jd) = JDEC::new(&mut inp, pool) { let _ = jd.set_scale(scale); - let _ = jd.decomp(&mut out); + let _ = jd.decomp(&mut inp, &mut out); } } @@ -50,9 +50,9 @@ pub fn jpeg_test(data: &[u8]) -> bool { } let mut out = BlackHoleOutput; - let mut res = jd.decomp(&mut out); + let mut res = jd.decomp(&mut inp, &mut out); while res == Err(Error::Interrupted) { - res = jd.decomp(&mut out); + res = jd.decomp(&mut inp, &mut out); } res.is_ok() } else { diff --git a/core/embed/rust/src/ui/display/toif.rs b/core/embed/rust/src/ui/display/toif.rs index 150394573b..eff8808921 100644 --- a/core/embed/rust/src/ui/display/toif.rs +++ b/core/embed/rust/src/ui/display/toif.rs @@ -1,5 +1,5 @@ use crate::{ - error::Error, + error::{value_error, Error}, trezorhal::uzlib::{UzlibContext, UZLIB_WINDOW_SIZE}, ui::{ component::image::Image, @@ -208,11 +208,11 @@ impl<'i> Toif<'i> { pub const fn new(data: &'i [u8]) -> Result { if data.len() < TOIF_HEADER_LENGTH || data[0] != b'T' || data[1] != b'O' || data[2] != b'I' { - return Err(value_error!("Invalid TOIF header.")); + return Err(value_error!(c"Invalid TOIF header.")); } let zdatalen = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize; if zdatalen + TOIF_HEADER_LENGTH != data.len() { - return Err(value_error!("Invalid TOIF length.")); + return Err(value_error!(c"Invalid TOIF length.")); } Ok(Self { data, @@ -271,6 +271,10 @@ impl<'i> Toif<'i> { &self.data[TOIF_HEADER_LENGTH..] } + pub fn original_data(&self) -> &'i [u8] { + self.data + } + pub fn uncompress(&self, dest: &mut [u8]) { let mut ctx = self.decompression_context(None); unwrap!(ctx.uncompress(dest)); diff --git a/core/embed/rust/src/ui/event.rs b/core/embed/rust/src/ui/event.rs index fd1f555543..a0b7587ef9 100644 --- a/core/embed/rust/src/ui/event.rs +++ b/core/embed/rust/src/ui/event.rs @@ -1,13 +1,18 @@ use crate::{error, ui::geometry::Point}; use core::convert::TryInto; +#[cfg(feature = "touch")] +use crate::ui::component::SwipeDirection; + #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub enum PhysicalButton { Left, Right, } #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub enum ButtonEvent { /// Button pressed down. /// ▼ * | * ▼ @@ -36,6 +41,7 @@ impl ButtonEvent { } #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub enum TouchEvent { /// A person has started touching the screen at given absolute coordinates. /// `TouchMove` will usually follow, and `TouchEnd` should finish the @@ -45,6 +51,8 @@ pub enum TouchEvent { TouchMove(Point), /// Touch has ended at a point on the screen. TouchEnd(Point), + /// Touch event has been suppressed by more important event - i.e. Swipe. + TouchAbort, } impl TouchEvent { @@ -61,7 +69,16 @@ impl TouchEvent { } #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub enum USBEvent { /// USB host has connected/disconnected. Connected(bool), } + +#[cfg(feature = "touch")] +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] +pub enum SwipeEvent { + Move(SwipeDirection, i16), + End(SwipeDirection), +} diff --git a/core/embed/rust/src/ui/flow/base.rs b/core/embed/rust/src/ui/flow/base.rs new file mode 100644 index 0000000000..eddfb80f26 --- /dev/null +++ b/core/embed/rust/src/ui/flow/base.rs @@ -0,0 +1,107 @@ +use crate::ui::component::{base::AttachType, swipe_detect::SwipeConfig, SwipeDirection}; + +pub use crate::ui::component::FlowMsg; + +pub trait Swipable { + fn get_swipe_config(&self) -> SwipeConfig; + + fn get_internal_page_count(&self) -> usize; +} + +/// Composable event handler result. +#[derive(Clone)] +pub enum Decision { + /// Do nothing, continue with processing next handler. + Nothing, + + /// Initiate transition to another state, end event processing. + /// NOTE: it might make sense to include Option here + Transition(AttachType), + + /// Yield a message to the caller of the flow (i.e. micropython), end event + /// processing. + Return(FlowMsg), +} + +impl Decision { + pub fn or_else(self, func: impl FnOnce() -> Self) -> Self { + match self { + Decision::Nothing => func(), + _ => self, + } + } +} + +/// State transition type. +/// +/// Contains a new state (by convention it must be of the same concrete type as +/// the current one) and a Decision object that tells the flow what to do next. +pub type StateChange = (&'static dyn FlowState, Decision); + +/// Encodes the flow logic as a set of states, and transitions between them +/// triggered by events and swipes. +pub trait FlowState { + /// What to do when user swipes on screen and current component doesn't + /// respond to swipe of that direction. + /// + /// By convention, the type of the new state inside the state change must be + /// Self. This can't be enforced by the type system unfortunately, because + /// this trait must remain object-safe and so can't refer to Self. + fn handle_swipe(&'static self, direction: SwipeDirection) -> StateChange; + + /// What to do when the current component emits a message in response to an + /// event. + /// + /// By convention, the type of the new state inside the state change must be + /// Self. This can't be enforced by the type system unfortunately, because + /// this trait must remain object-safe and so can't refer to Self. + fn handle_event(&'static self, msg: FlowMsg) -> StateChange; + + /// Page index of the current state. + fn index(&'static self) -> usize; +} + +/// Helper trait for writing nicer flow logic. +pub trait DecisionBuilder: FlowState + Sized { + #[inline] + fn swipe(&'static self, direction: SwipeDirection) -> StateChange { + (self, Decision::Transition(AttachType::Swipe(direction))) + } + + #[inline] + fn swipe_left(&'static self) -> StateChange { + self.swipe(SwipeDirection::Left) + } + + #[inline] + fn swipe_right(&'static self) -> StateChange { + self.swipe(SwipeDirection::Right) + } + + #[inline] + fn swipe_up(&'static self) -> StateChange { + self.swipe(SwipeDirection::Up) + } + + #[inline] + fn swipe_down(&'static self) -> StateChange { + self.swipe(SwipeDirection::Down) + } + + #[inline] + fn transit(&'static self) -> StateChange { + (self, Decision::Transition(AttachType::Initial)) + } + + #[inline] + fn do_nothing(&'static self) -> StateChange { + (self, Decision::Nothing) + } + + #[inline] + fn return_msg(&'static self, msg: FlowMsg) -> StateChange { + (self, Decision::Return(msg)) + } +} + +impl DecisionBuilder for T {} diff --git a/core/embed/rust/src/ui/flow/mod.rs b/core/embed/rust/src/ui/flow/mod.rs new file mode 100644 index 0000000000..cd01cd02d7 --- /dev/null +++ b/core/embed/rust/src/ui/flow/mod.rs @@ -0,0 +1,8 @@ +pub mod base; +pub mod page; +mod swipe; + +pub use crate::ui::component::FlowMsg; +pub use base::{FlowState, Swipable}; +pub use page::SwipePage; +pub use swipe::SwipeFlow; diff --git a/core/embed/rust/src/ui/flow/page.rs b/core/embed/rust/src/ui/flow/page.rs new file mode 100644 index 0000000000..b5138699c6 --- /dev/null +++ b/core/embed/rust/src/ui/flow/page.rs @@ -0,0 +1,102 @@ +use crate::ui::{ + component::{Component, Event, EventCtx, Paginate, SwipeDirection}, + event::SwipeEvent, + geometry::{Axis, Rect}, + shape::Renderer, +}; + +/// Allows any implementor of `Paginate` to be part of `Swipable` UI flow. +/// Renders sliding animation when changing pages. +pub struct SwipePage { + inner: T, + bounds: Rect, + axis: Axis, + pages: usize, + current: usize, +} + +impl SwipePage { + pub fn vertical(inner: T) -> Self { + Self { + inner, + bounds: Rect::zero(), + axis: Axis::Vertical, + pages: 1, + current: 0, + } + } + + pub fn horizontal(inner: T) -> Self { + Self { + inner, + bounds: Rect::zero(), + axis: Axis::Horizontal, + pages: 1, + current: 0, + } + } + + pub fn inner(&self) -> &T { + &self.inner + } +} + +impl Component for SwipePage { + type Msg = T::Msg; + + fn place(&mut self, bounds: Rect) -> Rect { + self.bounds = self.inner.place(bounds); + self.pages = self.inner.page_count(); + self.bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ctx.set_page_count(self.pages); + + if let Event::Swipe(SwipeEvent::End(direction)) = event { + match (self.axis, direction) { + (Axis::Vertical, SwipeDirection::Up) => { + self.current = (self.current + 1).min(self.pages - 1); + self.inner.change_page(self.current); + ctx.request_paint(); + } + (Axis::Vertical, SwipeDirection::Down) => { + self.current = self.current.saturating_sub(1); + self.inner.change_page(self.current); + ctx.request_paint(); + } + (Axis::Horizontal, SwipeDirection::Left) => { + self.current = (self.current + 1).min(self.pages - 1); + self.inner.change_page(self.current); + ctx.request_paint(); + } + (Axis::Horizontal, SwipeDirection::Right) => { + self.current = self.current.saturating_sub(1); + self.inner.change_page(self.current); + ctx.request_paint(); + } + _ => {} + } + } + + self.inner.event(ctx, event) + } + + fn paint(&mut self) { + self.inner.paint() + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.inner.render(target) + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for SwipePage +where + T: crate::trace::Trace, +{ + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + self.inner.trace(t) + } +} diff --git a/core/embed/rust/src/ui/flow/swipe.rs b/core/embed/rust/src/ui/flow/swipe.rs new file mode 100644 index 0000000000..b35f9ea065 --- /dev/null +++ b/core/embed/rust/src/ui/flow/swipe.rs @@ -0,0 +1,386 @@ +use crate::{ + error::{self, Error}, + maybe_trace::MaybeTrace, + micropython::{ + gc::{self, GcBox}, + obj::Obj, + }, + ui::{ + component::{ + base::{AttachType, AttachType::Swipe}, + swipe_detect::SwipeSettings, + Component, Event, EventCtx, FlowMsg, SwipeDetect, SwipeDetectMsg, SwipeDirection, + }, + display::Color, + event::{SwipeEvent, TouchEvent}, + flow::{base::Decision, FlowState}, + geometry::Rect, + layout::obj::ObjComponent, + shape::{render_on_display, ConcreteRenderer, Renderer, ScopedRenderer}, + util::animation_disabled, + }, +}; + +use super::{base::StateChange, Swipable}; + +use heapless::Vec; + +/// Component-like proto-object-safe trait. +/// +/// This copies the Component interface, but it is parametrized by a concrete +/// Renderer type, making it object-safe. +pub trait FlowComponentTrait<'s, R: Renderer<'s>>: Swipable { + fn place(&mut self, bounds: Rect) -> Rect; + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option; + fn render(&'s self, target: &mut R); + + #[cfg(feature = "ui_debug")] + fn trace(&self, t: &mut dyn crate::trace::Tracer); +} + +/// FlowComponentTrait implementation for Components. +/// +/// Components implementing FlowComponentTrait must: +/// * also implement Swipable, required by FlowComponentTrait, +/// * use FlowMsg as their Msg type, +/// * implement MaybeTrace to be able to conform to ObjComponent. +impl<'s, R, C> FlowComponentTrait<'s, R> for C +where + C: Component + MaybeTrace + Swipable, + R: Renderer<'s>, +{ + fn place(&mut self, bounds: Rect) -> Rect { + ::place(self, bounds) + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ::event(self, ctx, event) + } + + fn render(&'s self, target: &mut R) { + ::render(self, target) + } + + #[cfg(feature = "ui_debug")] + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + ::trace(self, t) + } +} + +/// Shortcut type for the concrete renderer passed into `render()` method. +type RendererImpl<'a, 'alloc, 'env> = ScopedRenderer<'alloc, 'env, ConcreteRenderer<'a, 'alloc>>; + +/// Fully object-safe component-like trait for flow components. +/// +/// This trait has no generic parameters: +/// * it is instantiated with a concrete Renderer type, and +/// * it requires the `FlowComponentTrait` trait to be implemented for _any_ +/// lifetimes. +pub trait FlowComponentDynTrait: + for<'a, 'alloc, 'env> FlowComponentTrait<'alloc, RendererImpl<'a, 'alloc, 'env>> +{ +} + +impl FlowComponentDynTrait for T where + T: for<'a, 'alloc, 'env> FlowComponentTrait<'alloc, RendererImpl<'a, 'alloc, 'env>> +{ +} + +/// Swipe flow consisting of multiple screens. +/// +/// Implements swipe navigation between the states with animated transitions, +/// based on state transitions provided by the FlowState type. +/// +/// If a swipe is detected: +/// - currently active component is asked to handle the event, +/// - if it can't then FlowState::handle_swipe is consulted. +pub struct SwipeFlow { + /// Current state of the flow. + state: &'static dyn FlowState, + /// Store of all screens which are part of the flow. + store: Vec, 12>, + /// Swipe detector. + swipe: SwipeDetect, + /// Swipe allowed + allow_swipe: bool, + /// Current internal state + internal_state: u16, + /// Internal pages count + internal_pages: u16, + /// If triggering swipe by event, make this decision instead of default + /// after the swipe. + decision_override: Option, +} + +impl SwipeFlow { + pub fn new(initial_state: &'static dyn FlowState) -> Result { + Ok(Self { + state: initial_state, + swipe: SwipeDetect::new(), + store: Vec::new(), + allow_swipe: true, + internal_state: 0, + internal_pages: 1, + decision_override: None, + }) + } + + /// Add a page to the flow. + /// + /// Pages must be inserted in the order of the flow state index. + pub fn with_page( + mut self, + state: &'static dyn FlowState, + page: impl FlowComponentDynTrait + 'static, + ) -> Result { + debug_assert!(self.store.len() == state.index()); + let alloc = GcBox::new(page)?; + let page = gc::coerce!(FlowComponentDynTrait, alloc); + unwrap!(self.store.push(page)); + Ok(self) + } + + fn current_page(&self) -> &GcBox { + &self.store[self.state.index()] + } + + fn current_page_mut(&mut self) -> &mut GcBox { + &mut self.store[self.state.index()] + } + + fn goto(&mut self, ctx: &mut EventCtx, attach_type: AttachType) { + self.swipe = SwipeDetect::new(); + self.allow_swipe = true; + + self.current_page_mut() + .event(ctx, Event::Attach(attach_type)); + + self.internal_pages = self.current_page_mut().get_internal_page_count() as u16; + + match attach_type { + Swipe(SwipeDirection::Up) => { + self.internal_state = 0; + } + Swipe(SwipeDirection::Down) => { + self.internal_state = self.internal_pages.saturating_sub(1); + } + _ => {} + } + + ctx.request_paint(); + } + + fn render_state<'s>(&'s self, state: usize, target: &mut RendererImpl<'_, 's, '_>) { + self.store[state].render(target); + } + + fn handle_swipe_child( + &mut self, + _ctx: &mut EventCtx, + direction: SwipeDirection, + ) -> StateChange { + self.state.handle_swipe(direction) + } + + fn handle_event_child(&mut self, ctx: &mut EventCtx, event: Event) -> StateChange { + let msg = self.current_page_mut().event(ctx, event); + + if let Some(msg) = msg { + self.state.handle_event(msg) + } else { + (self.state, Decision::Nothing) + } + } + + fn state_unchanged(&self) -> StateChange { + (self.state, Decision::Nothing) + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + let mut state_change = self.state_unchanged(); + let mut return_transition: AttachType = AttachType::Initial; + + let mut attach = false; + + let e = if self.allow_swipe { + let page = self.current_page(); + let mut config = page.get_swipe_config(); + + self.internal_pages = page.get_internal_page_count() as u16; + + // add additional swipe directions if there are more internal pages + // todo can we get internal settings from config somehow? + // might wanna different duration or something + if config.vertical_pages && self.internal_state > 0 { + config = config.with_swipe(SwipeDirection::Down, SwipeSettings::default()) + } + if config.horizontal_pages && self.internal_state > 0 { + config = config.with_swipe(SwipeDirection::Right, SwipeSettings::default()) + } + if config.vertical_pages && self.internal_state < self.internal_pages - 1 { + config = config.with_swipe(SwipeDirection::Up, SwipeSettings::default()) + } + if config.horizontal_pages && self.internal_state < self.internal_pages - 1 { + config = config.with_swipe(SwipeDirection::Left, SwipeSettings::default()) + } + + match self.swipe.event(ctx, event, config) { + Some(SwipeDetectMsg::Trigger(dir)) => { + if let Some(override_decision) = self.decision_override.take() { + state_change = override_decision; + } else { + state_change = self.handle_swipe_child(ctx, dir); + } + + return_transition = AttachType::Swipe(dir); + + let states_num = self.internal_pages; + if states_num > 0 { + if config.has_horizontal_pages() { + let current_state = self.internal_state; + if dir == SwipeDirection::Left && current_state < states_num - 1 { + self.internal_state += 1; + state_change = self.state_unchanged(); + attach = true; + } else if dir == SwipeDirection::Right && current_state > 0 { + self.internal_state -= 1; + state_change = self.state_unchanged(); + attach = true; + } + } + if config.has_vertical_pages() { + let current_state = self.internal_state; + if dir == SwipeDirection::Up && current_state < states_num - 1 { + self.internal_state += 1; + state_change = self.state_unchanged(); + attach = true; + } else if dir == SwipeDirection::Down && current_state > 0 { + self.internal_state -= 1; + state_change = self.state_unchanged(); + attach = true; + } + } + } + + Event::Swipe(SwipeEvent::End(dir)) + } + Some(SwipeDetectMsg::Move(dir, progress)) => { + Event::Swipe(SwipeEvent::Move(dir, progress as i16)) + } + Some(SwipeDetectMsg::Start(_)) => Event::Touch(TouchEvent::TouchAbort), + _ => event, + } + } else { + event + }; + + match state_change { + (_, Decision::Nothing) => { + state_change = self.handle_event_child(ctx, e); + + // when doing internal transition, pass attach event to the child after sending + // swipe end. + if attach { + if let Event::Swipe(SwipeEvent::End(dir)) = e { + self.current_page_mut() + .event(ctx, Event::Attach(AttachType::Swipe(dir))); + } + } + + if ctx.disable_swipe_requested() { + self.swipe.reset(); + self.allow_swipe = false; + } + if ctx.enable_swipe_requested() { + self.swipe.reset(); + self.allow_swipe = true; + }; + + let config = self.current_page().get_swipe_config(); + + if let (_, Decision::Transition(Swipe(direction))) = state_change { + if config.is_allowed(direction) { + if !animation_disabled() { + self.swipe.trigger(ctx, direction, config); + self.decision_override = Some(state_change); + state_change = self.state_unchanged(); + } + self.allow_swipe = true; + } + } + } + _ => { + //ignore message, we are already transitioning + self.current_page_mut().event(ctx, event); + } + } + + let (new_state, decision) = state_change; + self.state = new_state; + match decision { + Decision::Transition(attach) => { + self.state = new_state; + self.goto(ctx, attach); + None + } + Decision::Return(msg) => { + ctx.set_transition_out(return_transition); + self.swipe.reset(); + self.allow_swipe = true; + Some(msg) + } + _ => None, + } + } +} + +/// ObjComponent implementation for SwipeFlow. +/// +/// Instead of using the generic `impl ObjComponent for ComponentMsgObj`, we +/// provide our own short-circuit implementation for `SwipeFlow`. This way we +/// can completely avoid implementing `Component`. That also allows us to pass +/// around concrete Renderers instead of having to conform to `Component`'s +/// not-object-safe interface. +/// +/// This implementation relies on the fact that swipe components always return +/// `FlowMsg` as their `Component::Msg` (provided by `impl FlowComponentTrait` +/// earlier in this file). +#[cfg(feature = "micropython")] +impl ObjComponent for SwipeFlow { + fn obj_place(&mut self, bounds: Rect) -> Rect { + for elem in self.store.iter_mut() { + elem.place(bounds); + } + bounds + } + + fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result { + match self.event(ctx, event) { + None => Ok(Obj::const_none()), + Some(FlowMsg::Confirmed) => Ok(crate::ui::layout::result::CONFIRMED.as_obj()), + Some(FlowMsg::Cancelled) => Ok(crate::ui::layout::result::CANCELLED.as_obj()), + Some(FlowMsg::Info) => Ok(crate::ui::layout::result::INFO.as_obj()), + Some(FlowMsg::Choice(i)) => { + Ok((crate::ui::layout::result::CONFIRMED.as_obj(), i.try_into()?).try_into()?) + } + Some(FlowMsg::Text(s)) => Ok(( + crate::ui::layout::result::CONFIRMED.as_obj(), + s.as_str().try_into()?, + ) + .try_into()?), + } + } + + fn obj_paint(&mut self) { + render_on_display(None, Some(Color::black()), |target| { + self.render_state(self.state.index(), target); + }); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for SwipeFlow { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + self.current_page().trace(t) + } +} diff --git a/core/embed/rust/src/ui/geometry.rs b/core/embed/rust/src/ui/geometry.rs index d73702340a..632b5811d0 100644 --- a/core/embed/rust/src/ui/geometry.rs +++ b/core/embed/rust/src/ui/geometry.rs @@ -1,5 +1,5 @@ use crate::ui::lerp::Lerp; -use core::ops::{Add, Neg, Sub}; +use core::ops::{Add, Mul, Neg, Sub}; const fn min(a: i16, b: i16) -> i16 { if a < b { @@ -128,15 +128,33 @@ impl Sub for Offset { } } +impl Mul for Offset { + type Output = Offset; + + fn mul(self, rhs: f32) -> Self::Output { + Offset::new( + (f32::from(self.x) * rhs) as i16, + (f32::from(self.y) * rhs) as i16, + ) + } +} + impl From for Offset { fn from(val: Point) -> Self { Offset::new(val.x, val.y) } } +impl Lerp for Offset { + fn lerp(a: Self, b: Self, t: f32) -> Self { + Offset::new(i16::lerp(a.x, b.x, t), i16::lerp(a.y, b.y, t)) + } +} + /// A point in 2D space defined by the the `x` and `y` coordinate. Relative /// coordinates, vectors, and offsets are represented by the `Offset` type. #[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "debug", derive(ufmt::derive::uDebug))] pub struct Point { pub x: i16, pub y: i16, @@ -545,6 +563,7 @@ pub enum Alignment { End, } +#[derive(Copy, Clone, PartialEq, Eq)] pub struct Alignment2D(pub Alignment, pub Alignment); impl Alignment2D { @@ -552,6 +571,8 @@ impl Alignment2D { pub const TOP_RIGHT: Alignment2D = Alignment2D(Alignment::End, Alignment::Start); pub const TOP_CENTER: Alignment2D = Alignment2D(Alignment::Center, Alignment::Start); pub const CENTER: Alignment2D = Alignment2D(Alignment::Center, Alignment::Center); + pub const CENTER_LEFT: Alignment2D = Alignment2D(Alignment::Start, Alignment::Center); + pub const CENTER_RIGHT: Alignment2D = Alignment2D(Alignment::End, Alignment::Center); pub const BOTTOM_LEFT: Alignment2D = Alignment2D(Alignment::Start, Alignment::End); pub const BOTTOM_RIGHT: Alignment2D = Alignment2D(Alignment::End, Alignment::End); pub const BOTTOM_CENTER: Alignment2D = Alignment2D(Alignment::Center, Alignment::End); diff --git a/core/embed/rust/src/ui/layout/obj.rs b/core/embed/rust/src/ui/layout/obj.rs index 9f7cb0e739..dc4f4a6741 100644 --- a/core/embed/rust/src/ui/layout/obj.rs +++ b/core/embed/rust/src/ui/layout/obj.rs @@ -1,34 +1,80 @@ use core::{ - cell::RefCell, + cell::{RefCell, RefMut}, convert::{TryFrom, TryInto}, + ops::{Deref, DerefMut}, }; +use num_traits::{FromPrimitive, ToPrimitive}; +#[cfg(feature = "button")] +use crate::ui::event::ButtonEvent; +#[cfg(feature = "touch")] +use crate::ui::{component::SwipeDirection, event::TouchEvent}; +#[cfg(feature = "new_rendering")] +use crate::ui::{display::Color, shape::render_on_display}; use crate::{ error::Error, maybe_trace::MaybeTrace, micropython::{ buffer::StrBuffer, - gc::Gc, + gc::{self, Gc, GcBox}, + macros::{obj_dict, obj_fn_1, obj_fn_2, obj_fn_3, obj_fn_var, obj_map, obj_type}, map::Map, obj::{Obj, ObjBase}, qstr::Qstr, + simple_type::SimpleTypeObj, typ::Type, util, }, time::Duration, ui::{ - component::{Component, Event, EventCtx, Never, Root, TimerToken}, - constant, - display::sync, + button_request::ButtonRequest, + component::{base::AttachType, Component, Event, EventCtx, Never, TimerToken}, + constant, display, + event::USBEvent, geometry::Rect, }, }; -#[cfg(feature = "button")] -use crate::ui::event::ButtonEvent; -#[cfg(feature = "touch")] -use crate::ui::event::TouchEvent; -use crate::ui::event::USBEvent; +impl AttachType { + fn to_obj(self) -> Obj { + match self { + Self::Initial => Obj::const_none(), + Self::Resume => 1u8.into(), + #[cfg(feature = "touch")] + Self::Swipe(dir) => (2u8 + unwrap!(dir.to_u8())).into(), + } + } + fn try_from_obj(obj: Obj) -> Result { + if obj == Obj::const_none() { + return Ok(Self::Initial); + } + let val: u8 = obj.try_into()?; + + match val { + 0 => Ok(Self::Initial), + 1 => Ok(Self::Resume), + #[cfg(feature = "touch")] + 2..=5 => Ok(Self::Swipe( + SwipeDirection::from_u8(val - 2).ok_or(Error::TypeError)?, + )), + _ => Err(Error::TypeError), + } + } +} + +static ATTACH_TYPE: Type = obj_type! { + name: Qstr::MP_QSTR_AttachType, + locals: &obj_dict!(obj_map! { + Qstr::MP_QSTR_INITIAL => Obj::small_int(0u16), + Qstr::MP_QSTR_RESUME => Obj::small_int(1u16), + Qstr::MP_QSTR_SWIPE_UP => Obj::small_int(2u16), + Qstr::MP_QSTR_SWIPE_DOWN => Obj::small_int(3u16), + Qstr::MP_QSTR_SWIPE_LEFT => Obj::small_int(4u16), + Qstr::MP_QSTR_SWIPE_RIGHT => Obj::small_int(5u16), + }), +}; + +pub static ATTACH_TYPE_OBJ: SimpleTypeObj = SimpleTypeObj::new(&ATTACH_TYPE); /// Conversion trait implemented by components that know how to convert their /// message values into MicroPython `Obj`s. @@ -46,15 +92,13 @@ pub trait ComponentMsgObj: Component { pub trait ObjComponent: MaybeTrace { fn obj_place(&mut self, bounds: Rect) -> Rect; fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result; - fn obj_paint(&mut self) -> bool; + fn obj_paint(&mut self); fn obj_bounds(&self, _sink: &mut dyn FnMut(Rect)) {} - fn obj_skip_paint(&mut self) {} - fn obj_request_clear(&mut self) {} } -impl ObjComponent for Root +impl ObjComponent for T where - T: ComponentMsgObj + MaybeTrace, + T: Component + ComponentMsgObj + MaybeTrace, { fn obj_place(&mut self, bounds: Rect) -> Rect { self.place(bounds) @@ -62,30 +106,32 @@ where fn obj_event(&mut self, ctx: &mut EventCtx, event: Event) -> Result { if let Some(msg) = self.event(ctx, event) { - self.inner().inner().msg_try_into_obj(msg) + self.msg_try_into_obj(msg) } else { Ok(Obj::const_none()) } } - fn obj_paint(&mut self) -> bool { - let will_paint = self.inner().will_paint(); - self.paint(); - will_paint - } - - #[cfg(feature = "ui_bounds")] - fn obj_bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.bounds(sink) - } + fn obj_paint(&mut self) { + #[cfg(not(feature = "new_rendering"))] + { + self.paint(); + } - fn obj_skip_paint(&mut self) { - self.skip_paint() + #[cfg(feature = "new_rendering")] + { + render_on_display(None, Some(Color::black()), |target| { + self.render(target); + }); + } } +} - fn obj_request_clear(&mut self) { - self.clear_screen() - } +#[derive(Copy, Clone, PartialEq, Eq)] +enum Repaint { + None, + Partial, + Full, } /// `LayoutObj` is a GC-allocated object exported to MicroPython, with type @@ -98,108 +144,130 @@ pub struct LayoutObj { } struct LayoutObjInner { - root: Gc, + root: Option>, event_ctx: EventCtx, timer_fn: Obj, page_count: u16, + repaint: Repaint, + transition_out: AttachType, } -impl LayoutObj { +impl LayoutObjInner { /// Create a new `LayoutObj`, wrapping a root component. - pub fn new(root: impl ComponentMsgObj + MaybeTrace + 'static) -> Result, Error> { - // Let's wrap the root component into a `Root` to maintain the top-level - // invalidation logic. - let wrapped_root = Root::new(root); - // SAFETY: We are coercing GC-allocated sized ptr into an unsized one. - let root = - unsafe { Gc::from_raw(Gc::into_raw(Gc::new(wrapped_root)?) as *mut dyn ObjComponent) }; - - Gc::new(Self { - base: Self::obj_type().as_base(), - inner: RefCell::new(LayoutObjInner { - root, - event_ctx: EventCtx::new(), - timer_fn: Obj::const_none(), - page_count: 1, - }), + #[inline(never)] + pub fn new(root: impl ObjComponent + 'static) -> Result { + let root = GcBox::new(root)?; + + Ok(Self { + root: Some(gc::coerce!(ObjComponent, root)), + event_ctx: EventCtx::new(), + timer_fn: Obj::const_none(), + page_count: 1, + repaint: Repaint::Full, + transition_out: AttachType::Initial, }) } - pub fn skip_first_paint(&self) { - let mut inner = self.inner.borrow_mut(); - - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - unsafe { Gc::as_mut(&mut inner.root) }.obj_skip_paint(); + fn obj_delete(&mut self) { + self.root = None; } /// Timer callback is expected to be a callable object of the following /// form: `def timer(token: int, deadline_in_ms: int)`. - fn obj_set_timer_fn(&self, timer_fn: Obj) { - self.inner.borrow_mut().timer_fn = timer_fn; + fn obj_set_timer_fn(&mut self, timer_fn: Obj) { + self.timer_fn = timer_fn; + } + + fn root(&self) -> &impl Deref { + unwrap!(self.root.as_ref()) + } + + fn root_mut(&mut self) -> &mut impl DerefMut { + unwrap!(self.root.as_mut()) + } + + fn obj_request_repaint(&mut self) { + self.repaint = Repaint::Full; + let mut dummy_ctx = EventCtx::new(); + let paint_msg = self + .root_mut() + .obj_event(&mut dummy_ctx, Event::RequestPaint); + // paint_msg must not be an error and it must not return a result + assert!(matches!(paint_msg, Ok(s) if s == Obj::const_none())); + // there must be no timers set + assert!(dummy_ctx.pop_timer().is_none()); } /// Run an event pass over the component tree. After the traversal, any /// pending timers are drained into `self.timer_callback`. Returns `Err` /// in case the timer callback raises or one of the components returns /// an error, `Ok` with the message otherwise. - fn obj_event(&self, event: Event) -> Result { - let inner = &mut *self.inner.borrow_mut(); - + fn obj_event(&mut self, event: Event) -> Result { + let root = unwrap!(self.root.as_mut()); // Place the root component on the screen in case it was previously requested. - if inner.event_ctx.needs_place_before_next_event_or_paint() { - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - unsafe { Gc::as_mut(&mut inner.root) }.obj_place(constant::screen()); + if self.event_ctx.needs_place() { + root.obj_place(constant::screen()); } // Clear the leftover flags from the previous event pass. - inner.event_ctx.clear(); + self.event_ctx.clear(); // Send the event down the component tree. Bail out in case of failure. - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - let msg = unsafe { Gc::as_mut(&mut inner.root) }.obj_event(&mut inner.event_ctx, event)?; + let msg = root.obj_event(&mut self.event_ctx, event)?; + + // Check if we should repaint next time + if self.event_ctx.needs_repaint_root() { + self.obj_request_repaint(); + } else if self.event_ctx.needs_repaint() { + self.repaint = Repaint::Partial; + } // All concerning `Child` wrappers should have already marked themselves for // painting by now, and we're prepared for a paint pass. // Drain any pending timers into the callback. - while let Some((token, deadline)) = inner.event_ctx.pop_timer() { + while let Some((token, deadline)) = self.event_ctx.pop_timer() { let token = token.try_into(); let deadline = deadline.try_into(); if let (Ok(token), Ok(deadline)) = (token, deadline) { - inner.timer_fn.call_with_n_args(&[token, deadline])?; + self.timer_fn.call_with_n_args(&[token, deadline])?; } else { // Failed to convert token or deadline into `Obj`, skip. } } - if let Some(count) = inner.event_ctx.page_count() { - inner.page_count = count as u16; + if let Some(count) = self.event_ctx.page_count() { + self.page_count = count as u16; } - Ok(msg) - } + if let Some(t) = self.event_ctx.get_transition_out() { + self.transition_out = t; + } - fn obj_request_clear(&self) { - let mut inner = self.inner.borrow_mut(); - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - unsafe { Gc::as_mut(&mut inner.root) }.obj_request_clear(); + Ok(msg) } /// Run a paint pass over the component tree. Returns true if any component /// actually requested painting since last invocation of the function. - fn obj_paint_if_requested(&self) -> bool { - let mut inner = self.inner.borrow_mut(); + fn obj_paint_if_requested(&mut self) -> bool { + if self.repaint == Repaint::Full { + display::clear(); + } // Place the root component on the screen in case it was previously requested. - if inner.event_ctx.needs_place_before_next_event_or_paint() { - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - unsafe { Gc::as_mut(&mut inner.root) }.obj_place(constant::screen()); + if self.event_ctx.needs_place() { + self.root_mut().obj_place(constant::screen()); } - sync(); + display::sync(); - // SAFETY: `inner.root` is unique because of the `inner.borrow_mut()`. - unsafe { Gc::as_mut(&mut inner.root) }.obj_paint() + if self.repaint != Repaint::None { + self.repaint = Repaint::None; + self.root_mut().obj_paint(); + true + } else { + false + } } /// Run a tracing pass over the component tree. Passed `callback` is called @@ -222,36 +290,47 @@ impl LayoutObj { // because trait upcasting is unstable. // Luckily, calling `root.trace()` works perfectly fine in spite of the above.) tracer.root(&|t| { - self.inner.borrow().root.trace(t); + self.root().trace(t); }); } fn obj_page_count(&self) -> Obj { - self.inner.borrow().page_count.into() + self.page_count.into() } - #[cfg(feature = "ui_debug")] - fn obj_bounds(&self) { - use crate::ui::display; - - // Sink for `Trace::bounds` that draws the boundaries using pseudorandom color. - fn wireframe(r: Rect) { - let w = r.width() as u16; - let h = r.height() as u16; - let color = display::Color::from_u16(w.rotate_right(w.into()).wrapping_add(h * 8)); - display::rect_stroke(r, color) + fn obj_button_request(&mut self) -> Result { + match self.event_ctx.button_request() { + None => Ok(Obj::const_none()), + Some(ButtonRequest { code, name }) => (code.num().into(), name.try_into()?).try_into(), + } + } + + fn obj_get_transition_out(&self) -> Obj { + self.transition_out.to_obj() + } +} + +impl LayoutObj { + /// Create a new `LayoutObj`, wrapping a root component. + pub fn new(root: impl ObjComponent + 'static) -> Result, Error> { + // SAFETY: This is a Python object and hase a base as first element + unsafe { + Gc::new_with_custom_finaliser(Self { + base: Self::obj_type().as_base(), + inner: RefCell::new(LayoutObjInner::new(root)?), + }) } + } - // use crate::ui::model_tt::theme; - // wireframe(theme::borders()); - self.inner.borrow().root.obj_bounds(&mut wireframe); + fn inner_mut(&self) -> RefMut { + self.inner.borrow_mut() } fn obj_type() -> &'static Type { static TYPE: Type = obj_type! { name: Qstr::MP_QSTR_LayoutObj, locals: &obj_dict!(obj_map! { - Qstr::MP_QSTR_attach_timer_fn => obj_fn_2!(ui_layout_attach_timer_fn).as_obj(), + Qstr::MP_QSTR_attach_timer_fn => obj_fn_3!(ui_layout_attach_timer_fn).as_obj(), Qstr::MP_QSTR_touch_event => obj_fn_var!(4, 4, ui_layout_touch_event).as_obj(), Qstr::MP_QSTR_button_event => obj_fn_var!(3, 3, ui_layout_button_event).as_obj(), Qstr::MP_QSTR_progress_event => obj_fn_var!(3, 3, ui_layout_progress_event).as_obj(), @@ -260,12 +339,18 @@ impl LayoutObj { Qstr::MP_QSTR_paint => obj_fn_1!(ui_layout_paint).as_obj(), Qstr::MP_QSTR_request_complete_repaint => obj_fn_1!(ui_layout_request_complete_repaint).as_obj(), Qstr::MP_QSTR_trace => obj_fn_2!(ui_layout_trace).as_obj(), - Qstr::MP_QSTR_bounds => obj_fn_1!(ui_layout_bounds).as_obj(), + Qstr::MP_QSTR___del__ => obj_fn_1!(ui_layout_delete).as_obj(), Qstr::MP_QSTR_page_count => obj_fn_1!(ui_layout_page_count).as_obj(), + Qstr::MP_QSTR_button_request => obj_fn_1!(ui_layout_button_request).as_obj(), + Qstr::MP_QSTR_get_transition_out => obj_fn_1!(ui_layout_get_transition_out).as_obj(), }), }; &TYPE } + + pub fn skip_first_paint(&self) { + self.inner_mut().repaint = Repaint::None; + } } impl From> for Obj { @@ -328,11 +413,14 @@ impl TryFrom for Obj { } } -extern "C" fn ui_layout_attach_timer_fn(this: Obj, timer_fn: Obj) -> Obj { +extern "C" fn ui_layout_attach_timer_fn(this: Obj, timer_fn: Obj, attach_type: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - this.obj_set_timer_fn(timer_fn); - let msg = this.obj_event(Event::Attach)?; + this.inner_mut().obj_set_timer_fn(timer_fn); + + let msg = this + .inner_mut() + .obj_event(Event::Attach(AttachType::try_from_obj(attach_type)?))?; assert!(msg == Obj::const_none()); Ok(Obj::const_none()) }; @@ -351,7 +439,7 @@ extern "C" fn ui_layout_touch_event(n_args: usize, args: *const Obj) -> Obj { args[2].try_into()?, args[3].try_into()?, )?; - let msg = this.obj_event(Event::Touch(event))?; + let msg = this.inner_mut().obj_event(Event::Touch(event))?; Ok(msg) }; unsafe { util::try_with_args_and_kwargs(n_args, args, &Map::EMPTY, block) } @@ -370,7 +458,7 @@ extern "C" fn ui_layout_button_event(n_args: usize, args: *const Obj) -> Obj { } let this: Gc = args[0].try_into()?; let event = ButtonEvent::new(args[1].try_into()?, args[2].try_into()?)?; - let msg = this.obj_event(Event::Button(event))?; + let msg = this.inner_mut().obj_event(Event::Button(event))?; Ok(msg) }; unsafe { util::try_with_args_and_kwargs(n_args, args, &Map::EMPTY, block) } @@ -389,7 +477,9 @@ extern "C" fn ui_layout_progress_event(n_args: usize, args: *const Obj) -> Obj { let this: Gc = args[0].try_into()?; let value: u16 = args[1].try_into()?; let description: StrBuffer = args[2].try_into()?; - let msg = this.obj_event(Event::Progress(value, description.into()))?; + let msg = this + .inner_mut() + .obj_event(Event::Progress(value, description.into()))?; Ok(msg) }; unsafe { util::try_with_args_and_kwargs(n_args, args, &Map::EMPTY, block) } @@ -402,7 +492,7 @@ extern "C" fn ui_layout_usb_event(n_args: usize, args: *const Obj) -> Obj { } let this: Gc = args[0].try_into()?; let event = USBEvent::Connected(args[1].try_into()?); - let msg = this.obj_event(Event::USB(event))?; + let msg = this.inner_mut().obj_event(Event::USB(event))?; Ok(msg) }; unsafe { util::try_with_args_and_kwargs(n_args, args, &Map::EMPTY, block) } @@ -412,7 +502,7 @@ extern "C" fn ui_layout_timer(this: Obj, token: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; let event = Event::Timer(token.try_into()?); - let msg = this.obj_event(event)?; + let msg = this.inner_mut().obj_event(event)?; Ok(msg) }; unsafe { util::try_or_raise(block) } @@ -421,7 +511,7 @@ extern "C" fn ui_layout_timer(this: Obj, token: Obj) -> Obj { extern "C" fn ui_layout_paint(this: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - let painted = this.obj_paint_if_requested().into(); + let painted = this.inner_mut().obj_paint_if_requested().into(); Ok(painted) }; unsafe { util::try_or_raise(block) } @@ -430,15 +520,7 @@ extern "C" fn ui_layout_paint(this: Obj) -> Obj { extern "C" fn ui_layout_request_complete_repaint(this: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - let event = Event::RequestPaint; - let msg = this.obj_event(event)?; - if msg != Obj::const_none() { - // Messages raised during a `RequestPaint` dispatch are not propagated, let's - // make sure we don't do that. - #[cfg(feature = "ui_debug")] - panic!("cannot raise messages during RequestPaint"); - }; - this.obj_request_clear(); + this.inner_mut().obj_request_repaint(); Ok(Obj::const_none()) }; unsafe { util::try_or_raise(block) } @@ -447,7 +529,26 @@ extern "C" fn ui_layout_request_complete_repaint(this: Obj) -> Obj { extern "C" fn ui_layout_page_count(this: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - Ok(this.obj_page_count()) + let page_count = this.inner_mut().obj_page_count(); + Ok(page_count) + }; + unsafe { util::try_or_raise(block) } +} + +extern "C" fn ui_layout_button_request(this: Obj) -> Obj { + let block = || { + let this: Gc = this.try_into()?; + let button_request = this.inner_mut().obj_button_request(); + button_request + }; + unsafe { util::try_or_raise(block) } +} + +extern "C" fn ui_layout_get_transition_out(this: Obj) -> Obj { + let block = || { + let this: Gc = this.try_into()?; + let transition_out = this.inner_mut().obj_get_transition_out(); + Ok(transition_out) }; unsafe { util::try_or_raise(block) } } @@ -462,7 +563,7 @@ pub extern "C" fn ui_debug_layout_type() -> &'static Type { extern "C" fn ui_layout_trace(this: Obj, callback: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - this.obj_trace(callback); + this.inner_mut().obj_trace(callback); Ok(Obj::const_none()) }; unsafe { util::try_or_raise(block) } @@ -473,17 +574,11 @@ extern "C" fn ui_layout_trace(_this: Obj, _callback: Obj) -> Obj { Obj::const_none() } -#[cfg(feature = "ui_bounds")] -extern "C" fn ui_layout_bounds(this: Obj) -> Obj { +extern "C" fn ui_layout_delete(this: Obj) -> Obj { let block = || { let this: Gc = this.try_into()?; - this.obj_bounds(); + this.inner_mut().obj_delete(); Ok(Obj::const_none()) }; unsafe { util::try_or_raise(block) } } - -#[cfg(not(feature = "ui_bounds"))] -extern "C" fn ui_layout_bounds(_this: Obj) -> Obj { - Obj::const_none() -} diff --git a/core/embed/rust/src/ui/layout/result.rs b/core/embed/rust/src/ui/layout/result.rs index f0dfb29f9f..bf91424b38 100644 --- a/core/embed/rust/src/ui/layout/result.rs +++ b/core/embed/rust/src/ui/layout/result.rs @@ -1,4 +1,4 @@ -use crate::micropython::{qstr::Qstr, simple_type::SimpleTypeObj, typ::Type}; +use crate::micropython::{macros::obj_type, qstr::Qstr, simple_type::SimpleTypeObj, typ::Type}; static CONFIRMED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CONFIRMED, }; static CANCELLED_TYPE: Type = obj_type! { name: Qstr::MP_QSTR_CANCELLED, }; diff --git a/core/embed/rust/src/ui/layout/simplified.rs b/core/embed/rust/src/ui/layout/simplified.rs index 412d644444..a966e1083a 100644 --- a/core/embed/rust/src/ui/layout/simplified.rs +++ b/core/embed/rust/src/ui/layout/simplified.rs @@ -1,7 +1,7 @@ #[cfg(feature = "button")] use crate::trezorhal::io::io_button_read; #[cfg(feature = "touch")] -use crate::trezorhal::io::io_touch_read; +use crate::trezorhal::io::io_touch_get_event; #[cfg(feature = "button")] use crate::ui::event::ButtonEvent; #[cfg(feature = "touch")] @@ -12,8 +12,12 @@ use crate::ui::{ ui_features::ModelUI, UIFeaturesCommon, }; + use num_traits::ToPrimitive; +#[cfg(feature = "new_rendering")] +use crate::ui::{display::color::Color, shape::render_on_display}; + pub trait ReturnToC { fn return_to_c(self) -> u32; } @@ -52,7 +56,7 @@ fn button_eval() -> Option { #[cfg(feature = "touch")] fn touch_eval() -> Option { - let event = io_touch_read(); + let event = io_touch_get_event(); if event == 0 { return None; } @@ -63,16 +67,28 @@ fn touch_eval() -> Option { TouchEvent::new(event_type, ex as _, ey as _).ok() } -pub fn run(frame: &mut F) -> u32 -where - F: Component, - F::Msg: ReturnToC, -{ +fn render(frame: &mut impl Component) { + #[cfg(not(feature = "new_rendering"))] + { + display::sync(); + frame.paint(); + display::refresh(); + } + + #[cfg(feature = "new_rendering")] + { + display::sync(); + render_on_display(None, Some(Color::black()), |target| { + frame.render(target); + }); + display::refresh(); + } +} + +pub fn run(frame: &mut impl Component) -> u32 { frame.place(ModelUI::SCREEN); ModelUI::fadeout(); - display::sync(); - frame.paint(); - display::refresh(); + render(frame); ModelUI::fadein(); #[cfg(feature = "button")] @@ -93,24 +109,20 @@ where if let Some(message) = msg { return message.return_to_c(); } - display::sync(); - frame.paint(); - display::refresh(); + render(frame); } } } -pub fn show(frame: &mut F, fading: bool) -where - F: Component, -{ +pub fn show(frame: &mut impl Component, fading: bool) { frame.place(ModelUI::SCREEN); + if fading { ModelUI::fadeout() }; - display::sync(); - frame.paint(); - display::refresh(); + + render(frame); + if fading { ModelUI::fadein() }; diff --git a/core/embed/rust/src/ui/layout/util.rs b/core/embed/rust/src/ui/layout/util.rs index b147158ad5..163dcbd730 100644 --- a/core/embed/rust/src/ui/layout/util.rs +++ b/core/embed/rust/src/ui/layout/util.rs @@ -1,5 +1,6 @@ use crate::{ - error::Error, + error::{value_error, Error}, + io::BinaryData, micropython::{ buffer::{hexlify_bytes, StrBuffer}, gc::Gc, @@ -24,6 +25,7 @@ use crate::{ /// consumption and conversion time. pub const MAX_HEX_CHARS_ON_SCREEN: usize = 256; +#[derive(Clone)] pub enum StrOrBytes { Str(TString<'static>), Bytes(Obj), @@ -54,6 +56,7 @@ impl TryFrom for StrOrBytes { } } +#[derive(Clone)] pub struct ConfirmBlob { pub description: TString<'static>, pub extra: TString<'static>, @@ -159,6 +162,41 @@ impl ParagraphSource<'static> for PropsList { } } +/// RecoveryType as defined in `common/protob/messages-management.proto`, +/// used as arguments coming from micropython into rust world for layouts or +/// flows. +pub enum RecoveryType { + Normal = 0, + DryRun = 1, + UnlockRepeatedBackup = 2, +} + +// Converting `Obj` into `RecoveryType` enum +#[cfg(feature = "micropython")] +impl TryFrom for RecoveryType { + type Error = Error; + + fn try_from(obj: Obj) -> Result { + let val = u32::try_from(obj)?; + let this = Self::try_from(val)?; + Ok(this) + } +} + +// Converting `u32` to `RecoveryType` +impl TryFrom for RecoveryType { + type Error = Error; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(RecoveryType::Normal), + 1 => Ok(RecoveryType::DryRun), + 2 => Ok(RecoveryType::UnlockRepeatedBackup), + _ => Err(value_error!(c"Invalid RecoveryType")), + } + } +} + pub extern "C" fn upy_disable_animation(disable: Obj) -> Obj { let block = || { set_animation_disabled(disable.try_into()?); @@ -167,10 +205,10 @@ pub extern "C" fn upy_disable_animation(disable: Obj) -> Obj { unsafe { try_or_raise(block) } } -pub fn get_user_custom_image() -> Result, Error> { +pub fn get_user_custom_image() -> Result, Error> { let len = get_avatar_len()?; let mut data = Gc::<[u8]>::new_slice(len)?; // SAFETY: buffer is freshly allocated so nobody else has it. load_avatar(unsafe { Gc::<[u8]>::as_mut(&mut data) })?; - Ok(data) + Ok(data.into()) } diff --git a/core/embed/rust/src/ui/lerp.rs b/core/embed/rust/src/ui/lerp.rs index 34d3802197..1f91efd2cb 100644 --- a/core/embed/rust/src/ui/lerp.rs +++ b/core/embed/rust/src/ui/lerp.rs @@ -25,7 +25,7 @@ pub trait InvLerp: Copy { fn inv_lerp(min: Self, max: Self, value: Self) -> f32; } -macro_rules! impl_lerp_for_int { +macro_rules! impl_lerp_for_signed { ($int: ident) => { impl Lerp for $int { fn lerp(a: Self, b: Self, t: f32) -> Self { @@ -41,7 +41,7 @@ macro_rules! impl_lerp_for_int { }; } -macro_rules! impl_lerp_for_uint { +macro_rules! impl_lerp_for_unsigned { ($uint: ident) => { impl Lerp for $uint { fn lerp(a: Self, b: Self, t: f32) -> Self { @@ -65,11 +65,13 @@ macro_rules! impl_lerp_for_uint { }; } -impl_lerp_for_int!(i16); -impl_lerp_for_int!(i32); -impl_lerp_for_uint!(u8); -impl_lerp_for_uint!(u16); -impl_lerp_for_uint!(u32); +impl_lerp_for_signed!(i16); +impl_lerp_for_signed!(i32); +impl_lerp_for_unsigned!(u8); +impl_lerp_for_unsigned!(u16); +impl_lerp_for_unsigned!(u32); + +impl_lerp_for_signed!(f32); #[cfg(test)] mod tests { diff --git a/core/embed/rust/src/ui/macros.rs b/core/embed/rust/src/ui/macros.rs deleted file mode 100644 index f286d8dcbd..0000000000 --- a/core/embed/rust/src/ui/macros.rs +++ /dev/null @@ -1,25 +0,0 @@ -#[allow(unused_macros)] // T1 doesn't use icons (yet) -macro_rules! include_res { - ($filename:expr) => { - include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/ui/", $filename)) - }; -} - -/// Concatenates arbitrary amount of slices into a String. -macro_rules! build_string { - ($max:expr, $($string:expr),+) => { - { - let mut new_string = String::<$max>::new(); - $(unwrap!(new_string.push_str($string));)+ - new_string - } - } -} - -/// Transforms integer into string slice. For example for printing. -#[allow(unused_macros)] // not used in TT UI -macro_rules! inttostr { - ($int:expr) => {{ - unwrap!(heapless::String::<10>::try_from($int)).as_str() - }}; -} diff --git a/core/embed/rust/src/ui/mod.rs b/core/embed/rust/src/ui/mod.rs index fd8c51dace..da52799582 100644 --- a/core/embed/rust/src/ui/mod.rs +++ b/core/embed/rust/src/ui/mod.rs @@ -1,14 +1,16 @@ -#[macro_use] -pub mod macros; - pub mod animation; +#[cfg(feature = "micropython")] +pub mod backlight; +pub mod button_request; pub mod component; pub mod constant; pub mod display; pub mod event; +#[cfg(all(feature = "micropython", feature = "touch", feature = "new_rendering"))] +pub mod flow; pub mod geometry; pub mod lerp; -#[macro_use] +pub mod shape; pub mod util; pub mod layout; diff --git a/core/embed/rust/src/ui/model_mercury/bootloader/intro.rs b/core/embed/rust/src/ui/model_mercury/bootloader/intro.rs index 91c8d95349..8fe0b39818 100644 --- a/core/embed/rust/src/ui/model_mercury/bootloader/intro.rs +++ b/core/embed/rust/src/ui/model_mercury/bootloader/intro.rs @@ -5,6 +5,7 @@ use crate::{ constant::screen, display::Icon, geometry::{Alignment, Insets, Point, Rect}, + shape::Renderer, }, }; @@ -43,7 +44,11 @@ impl<'a> Intro<'a> { .styled(button_bld_menu()) .with_expanded_touch_area(Insets::uniform(13)), ), - host: Child::new(Button::with_text("INSTALL FIRMWARE".into()).styled(button_bld())), + host: Child::new( + Button::with_text("INSTALL FIRMWARE".into()) + .styled(button_bld()) + .with_text_align(Alignment::Center), + ), text: Child::new(Label::left_aligned(content, TEXT_NORMAL).vertically_centered()), warn: (!fw_ok).then_some(Child::new( Label::new("FIRMWARE CORRUPTED".into(), Alignment::Start, TEXT_WARNING) @@ -106,8 +111,12 @@ impl<'a> Component for Intro<'a> { self.menu.paint(); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.menu.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.bg.render(target); + self.title.render(target); + self.text.render(target); + self.warn.render(target); + self.host.render(target); + self.menu.render(target); } } diff --git a/core/embed/rust/src/ui/model_mercury/bootloader/menu.rs b/core/embed/rust/src/ui/model_mercury/bootloader/menu.rs index ca4b3b94ae..97ab8857ae 100644 --- a/core/embed/rust/src/ui/model_mercury/bootloader/menu.rs +++ b/core/embed/rust/src/ui/model_mercury/bootloader/menu.rs @@ -5,6 +5,7 @@ use crate::{ constant::{screen, WIDTH}, display::Icon, geometry::{Insets, Point, Rect}, + shape::Renderer, }, }; @@ -108,10 +109,11 @@ impl Component for Menu { self.reset.paint(); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.close.bounds(sink); - self.reboot.bounds(sink); - self.reset.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.bg.render(target); + self.title.render(target); + self.close.render(target); + self.reboot.render(target); + self.reset.render(target); } } diff --git a/core/embed/rust/src/ui/model_mercury/bootloader/mod.rs b/core/embed/rust/src/ui/model_mercury/bootloader/mod.rs index f65f726f52..70d886400c 100644 --- a/core/embed/rust/src/ui/model_mercury/bootloader/mod.rs +++ b/core/embed/rust/src/ui/model_mercury/bootloader/mod.rs @@ -5,7 +5,7 @@ use crate::{ ui::{ component::{connect::Connect, Label}, display::{self, Color, Font, Icon}, - geometry::{Offset, Point, Rect}, + geometry::{Alignment, Offset, Point, Rect}, layout::simplified::{run, show}, }, }; @@ -16,6 +16,7 @@ use super::{ bl_confirm::{Confirm, ConfirmTitle}, Button, ResultScreen, WelcomeScreen, }, + theme, theme::{ bootloader::{ button_bld, button_bld_menu, button_confirm, button_wipe_cancel, button_wipe_confirm, @@ -23,12 +24,30 @@ use super::{ FIRE40, RESULT_FW_INSTALL, RESULT_WIPE, TEXT_BOLD, TEXT_NORMAL, TEXT_WIPE_BOLD, TEXT_WIPE_NORMAL, WARNING40, WELCOME_COLOR, X24, }, - BACKLIGHT_NORMAL, BLACK, GREEN_LIGHT, GREY, WHITE, + GREEN_LIGHT, GREY, }, ModelMercuryFeatures, }; use crate::ui::{ui_features::UIFeaturesBootloader, UIFeaturesCommon}; + +#[cfg(not(feature = "new_rendering"))] +use super::theme::BLACK; + +#[cfg(feature = "new_rendering")] +use crate::ui::{ + display::{toif::Toif, LOADER_MAX}, + geometry::Alignment2D, + model_mercury::cshape::{render_loader, LoaderRange}, + shape, + shape::render_on_display, +}; + +#[cfg(feature = "new_rendering")] +use ufmt::uwrite; + +#[cfg(feature = "new_rendering")] +use super::theme::bootloader::BLD_WARN_COLOR; use intro::Intro; use menu::Menu; @@ -44,6 +63,7 @@ const SCREEN: Rect = ModelMercuryFeatures::SCREEN; const PROGRESS_TEXT_ORIGIN: Point = Point::new(2, 28); impl ModelMercuryFeatures { + #[cfg(not(feature = "new_rendering"))] fn screen_progress( text: &str, progress: u16, @@ -77,6 +97,71 @@ impl ModelMercuryFeatures { Self::fadein(); } } + + #[cfg(feature = "new_rendering")] + fn screen_progress( + text: &str, + progress: u16, + initialize: bool, + fg_color: Color, + bg_color: Color, + icon: Option<(Icon, Color)>, + center_text: Option<&str>, + ) { + if initialize { + Self::fadeout(); + } + display::sync(); + + render_on_display(None, Some(bg_color), |target| { + shape::Text::new(PROGRESS_TEXT_ORIGIN, text) + .with_font(Font::NORMAL) + .with_fg(BLD_FG) + .render(target); + + let loader_offset: i16 = 19; + let center_text_offset: i16 = 10; + let center = SCREEN.center() + Offset::y(loader_offset); + let inactive_color = bg_color.blend(fg_color, 85); + let end = 360.0 * progress as f32 / 1000.0; + + render_loader( + center, + inactive_color, + fg_color, + bg_color, + if progress >= LOADER_MAX { + LoaderRange::Full + } else { + LoaderRange::FromTo(0.0, end) + }, + target, + ); + + if let Some((icon, color)) = icon { + shape::ToifImage::new(center, icon.toif) + .with_align(Alignment2D::CENTER) + .with_fg(color) + .render(target); + } + + if let Some(center_text) = center_text { + shape::Text::new( + SCREEN.center() + Offset::y(loader_offset + center_text_offset), + center_text, + ) + .with_align(Alignment::Center) + .with_font(Font::NORMAL) + .with_fg(GREY) + .render(target); + } + }); + + display::refresh(); + if initialize { + Self::fadein(); + } + } } impl UIFeaturesBootloader for ModelMercuryFeatures { @@ -85,12 +170,13 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { show(&mut frame, true); } + #[cfg(not(feature = "new_rendering"))] fn bld_continue_label(bg_color: Color) { display::text_center( Point::new(SCREEN.width() / 2, SCREEN.height() - 5), "click to continue ...", Font::NORMAL, - WHITE, + BLD_FG, bg_color, ); } @@ -127,8 +213,6 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { None, ); } - - display::refresh(); } fn screen_install_fail() { @@ -149,6 +233,7 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { fingerprint: &str, should_keep_seed: bool, is_newvendor: bool, + is_newinstall: bool, version_cmp: i32, ) -> u32 { let mut version_str: BootloaderString = String::new(); @@ -157,7 +242,9 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { unwrap!(version_str.push_str("\nby ")); unwrap!(version_str.push_str(vendor)); - let title_str = if is_newvendor { + let title_str = if is_newinstall { + "INSTALL FIRMWARE" + } else if is_newvendor { "CHANGE FW\nVENDOR" } else if version_cmp > 0 { "UPDATE FIRMWARE" @@ -174,12 +261,20 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { )); let (left, right) = if should_keep_seed { - let l = Button::with_text("CANCEL".into()).styled(button_bld()); - let r = Button::with_text("INSTALL".into()).styled(button_confirm()); + let l = Button::with_text("CANCEL".into()) + .styled(button_bld()) + .with_text_align(Alignment::Center); + let r = Button::with_text("INSTALL".into()) + .styled(button_confirm()) + .with_text_align(Alignment::Center); (l, r) } else { - let l = Button::with_icon(Icon::new(X24)).styled(button_bld()); - let r = Button::with_icon(Icon::new(CHECK24)).styled(button_confirm()); + let l = Button::with_icon(Icon::new(X24)) + .styled(button_bld()) + .with_text_align(Alignment::Center); + let r = Button::with_icon(Icon::new(CHECK24)) + .styled(button_confirm()) + .with_text_align(Alignment::Center); (l, r) }; @@ -206,8 +301,12 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { ); let alert = Label::centered("SEED AND FIRMWARE\nWILL BE ERASED!".into(), TEXT_WIPE_BOLD); - let right = Button::with_text("RESET".into()).styled(button_wipe_confirm()); - let left = Button::with_text("CANCEL".into()).styled(button_wipe_cancel()); + let right = Button::with_text("RESET".into()) + .styled(button_wipe_confirm()) + .with_text_align(Alignment::Center); + let left = Button::with_text("CANCEL".into()) + .styled(button_wipe_cancel()) + .with_text_align(Alignment::Center); let mut frame = Confirm::new(BLD_WIPE_COLOR, left, right, ConfirmTitle::Icon(icon), msg) .with_alert(alert); @@ -216,11 +315,32 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { } fn screen_unlock_bootloader_confirm() -> u32 { - unimplemented!(); + let title = + Label::left_aligned("UNLOCK BOOTLOADER".into(), TEXT_BOLD).vertically_centered(); + let msg = Label::centered("This action cannot be undone!".into(), TEXT_NORMAL); + + let right = Button::with_text("UNLOCK".into()) + .styled(button_confirm()) + .with_text_align(Alignment::Center); + let left = Button::with_text("CANCEL".into()) + .styled(button_bld()) + .with_text_align(Alignment::Center); + + let mut frame = Confirm::new(BLD_BG, left, right, ConfirmTitle::Text(title), msg); + + run(&mut frame) } fn screen_unlock_bootloader_success() { - unimplemented!(); + let mut frame = ResultScreen::new( + &RESULT_FW_INSTALL, + Icon::new(CHECK40), + "Bootloader unlocked".into(), + Label::centered(RECONNECT_MESSAGE.into(), RESULT_FW_INSTALL.title_style()) + .vertically_centered(), + true, + ); + show(&mut frame, true); } fn screen_menu(firmware_present: secbool) -> u32 { @@ -252,6 +372,7 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { Self::fadeout(); } + #[cfg(not(feature = "new_rendering"))] display::rect_fill(SCREEN, BLACK); let mut frame = WelcomeScreen::new(); @@ -260,9 +381,8 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { if fading { Self::fadein(); } else { - display::set_backlight(BACKLIGHT_NORMAL); + display::set_backlight(theme::backlight::get_backlight_normal()); } - display::refresh(); } fn screen_wipe_progress(progress: u16, initialize: bool) { @@ -322,4 +442,89 @@ impl UIFeaturesBootloader for ModelMercuryFeatures { ); show(&mut frame, true); } + + #[cfg(feature = "new_rendering")] + fn screen_boot( + warning: bool, + vendor_str: Option<&str>, + version: [u8; 4], + vendor_img: &'static [u8], + wait: i32, + ) { + let bg_color = if warning { BLD_WARN_COLOR } else { BLD_BG }; + + display::sync(); + + render_on_display(None, Some(bg_color), |target| { + // Draw vendor image if it's valid and has size of 120x120 + if let Ok(toif) = Toif::new(vendor_img) { + if (toif.width() == 120) && (toif.height() == 120) { + // Image position depends on the vendor string presence + let pos = if vendor_str.is_some() { + Point::new(SCREEN.width() / 2, 30) + } else { + Point::new(SCREEN.width() / 2, 60) + }; + + shape::ToifImage::new(pos, toif) + .with_align(Alignment2D::TOP_CENTER) + .with_fg(BLD_FG) + .render(target); + } + } + + // Draw vendor string if present + if let Some(text) = vendor_str { + let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5 - 50); + shape::Text::new(pos, text) + .with_align(Alignment::Center) + .with_font(Font::NORMAL) + .with_fg(BLD_FG) //COLOR_BL_BG + .render(target); + + let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5 - 25); + + let mut version_text: BootloaderString = String::new(); + unwrap!(uwrite!( + version_text, + "{}.{}.{}", + version[0], + version[1], + version[2] + )); + + shape::Text::new(pos, version_text.as_str()) + .with_align(Alignment::Center) + .with_font(Font::NORMAL) + .with_fg(BLD_FG) + .render(target); + } + + // Draw a message + match wait.cmp(&0) { + core::cmp::Ordering::Equal => {} + core::cmp::Ordering::Greater => { + let mut text: BootloaderString = String::new(); + unwrap!(uwrite!(text, "starting in {} s", wait)); + + let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5); + shape::Text::new(pos, text.as_str()) + .with_align(Alignment::Center) + .with_font(Font::NORMAL) + .with_fg(BLD_FG) + .render(target); + } + core::cmp::Ordering::Less => { + let pos = Point::new(SCREEN.width() / 2, SCREEN.height() - 5); + shape::Text::new(pos, "click to continue ...") + .with_align(Alignment::Center) + .with_font(Font::NORMAL) + .with_fg(BLD_FG) + .render(target); + } + } + }); + + display::refresh(); + } } diff --git a/core/embed/rust/src/ui/model_mercury/bootloader/welcome.rs b/core/embed/rust/src/ui/model_mercury/bootloader/welcome.rs index 0e0321fd2a..3900459163 100644 --- a/core/embed/rust/src/ui/model_mercury/bootloader/welcome.rs +++ b/core/embed/rust/src/ui/model_mercury/bootloader/welcome.rs @@ -3,6 +3,8 @@ use crate::ui::{ constant::screen, display::{self, Font}, geometry::{Offset, Point, Rect}, + shape, + shape::Renderer, }; use super::super::theme::{BLACK, GREY, WHITE}; @@ -61,4 +63,33 @@ impl Component for Welcome { BLACK, ); } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.bg.render(target); + + shape::Text::new(TEXT_ORIGIN, "Get started") + .with_font(Font::NORMAL) + .with_fg(GREY) + .render(target); + + shape::Text::new(TEXT_ORIGIN + Offset::y(STRIDE), "with your Trezor") + .with_font(Font::NORMAL) + .with_fg(GREY) + .render(target); + + shape::Text::new(TEXT_ORIGIN + Offset::y(2 * STRIDE), "at") + .with_font(Font::NORMAL) + .with_fg(GREY) + .render(target); + + let at_width = Font::NORMAL.text_width("at "); + + shape::Text::new( + TEXT_ORIGIN + Offset::new(at_width, 2 * STRIDE), + "trezor.io/start", + ) + .with_font(Font::NORMAL) + .with_fg(WHITE) + .render(target); + } } diff --git a/core/embed/rust/src/ui/model_mercury/component/address_details.rs b/core/embed/rust/src/ui/model_mercury/component/address_details.rs new file mode 100644 index 0000000000..d5149f4d65 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/address_details.rs @@ -0,0 +1,216 @@ +use heapless::Vec; + +use crate::{ + error::Error, + strutil::TString, + translations::TR, + ui::{ + component::{ + swipe_detect::{SwipeConfig, SwipeSettings}, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs, VecExt}, + Component, Event, EventCtx, Paginate, SwipeDirection, + }, + event::SwipeEvent, + flow::Swipable, + geometry::Rect, + shape::Renderer, + }, +}; + +use super::{theme, Frame, FrameMsg}; + +const MAX_XPUBS: usize = 16; + +#[derive(Clone)] +pub struct AddressDetails { + details: Frame>>, + xpub_view: Frame>>, + xpubs: Vec<(TString<'static>, TString<'static>), MAX_XPUBS>, + xpub_page_count: Vec, + current_page: usize, +} + +impl AddressDetails { + pub fn new( + details_title: TString<'static>, + account: Option>, + path: Option>, + ) -> Result { + let mut para = ParagraphVecShort::new(); + if let Some(a) = account { + para.add(Paragraph::new::( + &theme::TEXT_SUB_GREY, + TR::words__account.into(), + )); + para.add(Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, a)); + } + if account.is_some() & path.is_some() { + para.add(Paragraph::new( + &theme::TEXT_SUB_GREY, + TString::from_str(" "), + )); + } + if let Some(p) = path { + para.add(Paragraph::new::( + &theme::TEXT_SUB_GREY, + TR::address_details__derivation_path.into(), + )); + para.add(Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, p)); + } + let result = Self { + details: Frame::left_aligned(details_title, para.into_paragraphs()) + .with_cancel_button() + .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) + .with_horizontal_pages(), + xpub_view: Frame::left_aligned( + " \n ".into(), + Paragraph::new(&theme::TEXT_MONO_GREY_LIGHT, "").into_paragraphs(), + ) + .with_cancel_button() + .with_horizontal_pages(), + xpubs: Vec::new(), + xpub_page_count: Vec::new(), + current_page: 0, + }; + Ok(result) + } + + pub fn add_xpub( + &mut self, + title: TString<'static>, + xpub: TString<'static>, + ) -> Result<(), Error> { + self.xpubs + .push((title, xpub)) + .map_err(|_| Error::OutOfRange) + } + + fn switch_xpub(&mut self, i: usize, page: usize) -> usize { + // Context is needed for updating child so that it can request repaint. In this + // case the parent component that handles paging always requests complete + // repaint after page change so we can use a dummy context here. + let mut dummy_ctx = EventCtx::new(); + self.xpub_view.update_title(&mut dummy_ctx, self.xpubs[i].0); + self.xpub_view.update_content(&mut dummy_ctx, |_ctx, p| { + p.inner_mut().update(self.xpubs[i].1); + let npages = p.page_count(); + p.change_page(page); + npages + }) + } + + fn lookup(&self, scrollbar_page: usize) -> (usize, usize) { + let mut xpub_index = 0; + let mut xpub_page = scrollbar_page; + for page_count in self.xpub_page_count.iter().map(|pc| { + let upc: usize = (*pc).into(); + upc + }) { + if page_count <= xpub_page { + xpub_page -= page_count; + xpub_index += 1; + } else { + break; + } + } + (xpub_index, xpub_page) + } +} + +impl Paginate for AddressDetails { + fn page_count(&mut self) -> usize { + self.get_internal_page_count() + } + + fn change_page(&mut self, to_page: usize) { + self.current_page = to_page; + if to_page > 0 { + let i = to_page - 1; + let (xpub_index, xpub_page) = self.lookup(i); + self.switch_xpub(xpub_index, xpub_page); + } + } +} + +impl Component for AddressDetails { + type Msg = (); + + fn place(&mut self, bounds: Rect) -> Rect { + self.details.place(bounds); + self.xpub_view.place(bounds); + + self.xpub_page_count.clear(); + for i in 0..self.xpubs.len() { + let npages = self.switch_xpub(i, 0) as u8; + unwrap!(self.xpub_page_count.push(npages)); + } + + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + ctx.set_page_count(self.page_count()); + match event { + Event::Swipe(SwipeEvent::End(SwipeDirection::Right)) => { + let to_page = self.current_page.saturating_sub(1); + self.change_page(to_page); + } + Event::Swipe(SwipeEvent::End(SwipeDirection::Left)) => { + let to_page = self + .current_page + .saturating_add(1) + .min(self.page_count() - 1); + self.change_page(to_page); + } + _ => {} + } + + let msg = match self.current_page { + 0 => self.details.event(ctx, event), + _ => self.xpub_view.event(ctx, event), + }; + match msg { + Some(FrameMsg::Button(_)) => Some(()), + _ => None, + } + } + + fn paint(&mut self) { + match self.current_page { + 0 => self.details.paint(), + _ => self.xpub_view.paint(), + } + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + match self.current_page { + 0 => self.details.render(target), + _ => self.xpub_view.render(target), + } + } +} + +impl Swipable for AddressDetails { + fn get_swipe_config(&self) -> SwipeConfig { + match self.current_page { + 0 => self.details.get_swipe_config(), + _ => self.xpub_view.get_swipe_config(), + } + } + + fn get_internal_page_count(&self) -> usize { + let total_xpub_pages: u8 = self.xpub_page_count.iter().copied().sum(); + 1usize.saturating_add(total_xpub_pages.into()) + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for AddressDetails { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("AddressDetails"); + match self.current_page { + 0 => t.child("details", &self.details), + _ => t.child("xpub_view", &self.xpub_view), + } + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs b/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs new file mode 100644 index 0000000000..b1a8495e68 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/binary_selection.rs @@ -0,0 +1,94 @@ +use crate::ui::{ + component::{Component, Event, EventCtx}, + geometry::{Alignment, Alignment2D, Offset, Rect}, + shape::Renderer, +}; + +use super::{super::cshape, theme, Button, ButtonContent, ButtonMsg, ButtonStyleSheet}; + +pub enum BinarySelectionMsg { + Left, + Right, +} + +/// Component presenting a binary choice represented as two buttons, left and +/// right. Both buttons are parameterized with content and style. +#[derive(Clone)] +pub struct BinarySelection { + buttons_area: Rect, + button_left: Button, + button_right: Button, +} + +impl BinarySelection { + pub fn new( + left_content: ButtonContent, + right_content: ButtonContent, + left_style: ButtonStyleSheet, + right_style: ButtonStyleSheet, + ) -> Self { + Self { + buttons_area: Rect::zero(), + button_left: Button::new(left_content) + .styled(left_style) + .with_text_align(Alignment::Center), + button_right: Button::new(right_content) + .styled(right_style) + .with_text_align(Alignment::Center), + } + } +} + +impl Component for BinarySelection { + type Msg = BinarySelectionMsg; + + fn place(&mut self, bounds: Rect) -> Rect { + // Ensure reasonable space. Other than that, this component fits itself into any + // bounds. + let bounds_width = bounds.width(); + let bounds_height = bounds.height(); + assert!(bounds_width > 62); + assert!(bounds_height > 30); + + let buttons_area = Rect::snap( + bounds.center(), + Offset::new(bounds_width, theme::BUTTON_HEIGHT.min(bounds_height)), + Alignment2D::CENTER, + ); + let (left_area, _, right_area) = buttons_area.split_center(theme::SPACING); + self.button_left.place(left_area); + self.button_right.place(right_area); + + self.buttons_area = buttons_area; + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if let Some(ButtonMsg::Clicked) = self.button_left.event(ctx, event) { + return Some(BinarySelectionMsg::Left); + } + if let Some(ButtonMsg::Clicked) = self.button_right.event(ctx, event) { + return Some(BinarySelectionMsg::Right); + } + None + } + + fn paint(&mut self) { + unimplemented!() + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.button_left.render(target); + self.button_right.render(target); + cshape::KeyboardOverlay::new(self.buttons_area).render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for BinarySelection { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("BinarySelection"); + t.child("button_left", &self.button_left); + t.child("button_right", &self.button_right); + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/bl_confirm.rs b/core/embed/rust/src/ui/model_mercury/component/bl_confirm.rs index 6e33e5dc5e..d48d2cce47 100644 --- a/core/embed/rust/src/ui/model_mercury/component/bl_confirm.rs +++ b/core/embed/rust/src/ui/model_mercury/component/bl_confirm.rs @@ -6,6 +6,8 @@ use crate::{ constant::screen, display::{Color, Icon}, geometry::{Alignment2D, Insets, Offset, Point, Rect}, + shape, + shape::Renderer, }, }; @@ -239,10 +241,38 @@ impl Component for Confirm<'_> { } } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - self.left_button.bounds(sink); - self.right_button.bounds(sink); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.bg.render(target); + self.content_pad.render(target); + + if let Some(info) = self.info.as_ref() { + if self.show_info { + info.close_button.render(target); + info.title.render(target); + info.text.render(target); + self.left_button.render(target); + self.right_button.render(target); + // short-circuit before painting the main components + return; + } else { + info.info_button.render(target); + // pass through to the rest of the paint + } + } + + self.message.render(target); + self.alert.render(target); + self.left_button.render(target); + self.right_button.render(target); + match &self.title { + ConfirmTitle::Text(label) => label.render(target), + ConfirmTitle::Icon(icon) => { + shape::ToifImage::new(Point::new(screen().center().x, ICON_TOP), icon.toif) + .with_align(Alignment2D::TOP_CENTER) + .with_fg(WHITE) + .render(target); + } + } } } diff --git a/core/embed/rust/src/ui/model_mercury/component/button.rs b/core/embed/rust/src/ui/model_mercury/component/button.rs index 747f994f6f..5ff30c0fbb 100644 --- a/core/embed/rust/src/ui/model_mercury/component/button.rs +++ b/core/embed/rust/src/ui/model_mercury/component/button.rs @@ -7,7 +7,9 @@ use crate::{ component::{Component, Event, EventCtx, TimerToken}, display::{self, toif::Icon, Color, Font}, event::TouchEvent, - geometry::{Alignment2D, Insets, Offset, Point, Rect}, + geometry::{Alignment, Alignment2D, Insets, Offset, Point, Rect}, + shape, + shape::Renderer, }, }; @@ -20,20 +22,25 @@ pub enum ButtonMsg { LongPressed, } +#[derive(Clone)] pub struct Button { area: Rect, touch_expand: Option, content: ButtonContent, styles: ButtonStyleSheet, + text_align: Alignment, + radius: Option, state: State, long_press: Option, long_timer: Option, + haptic: bool, } impl Button { - /// Offsets the baseline of the button text either up (negative) or down - /// (positive). - pub const BASELINE_OFFSET: i16 = -2; + /// Offsets the baseline of the button text + /// -x/+x => left/right + /// -y/+y => up/down + pub const BASELINE_OFFSET: Offset = Offset::new(2, 6); pub const fn new(content: ButtonContent) -> Self { Self { @@ -41,9 +48,12 @@ impl Button { area: Rect::zero(), touch_expand: None, styles: theme::button_default(), + text_align: Alignment::Start, + radius: None, state: State::Initial, long_press: None, long_timer: None, + haptic: true, } } @@ -59,10 +69,6 @@ impl Button { Self::new(ButtonContent::IconAndText(content)) } - pub const fn with_icon_blend(bg: Icon, fg: Icon, fg_offset: Offset) -> Self { - Self::new(ButtonContent::IconBlend(bg, fg, fg_offset)) - } - pub const fn empty() -> Self { Self::new(ButtonContent::Empty) } @@ -72,6 +78,11 @@ impl Button { self } + pub const fn with_text_align(mut self, align: Alignment) -> Self { + self.text_align = align; + self + } + pub const fn with_expanded_touch_area(mut self, expand: Insets) -> Self { self.touch_expand = Some(expand); self @@ -82,6 +93,16 @@ impl Button { self } + pub fn with_radius(mut self, radius: u8) -> Self { + self.radius = Some(radius); + self + } + + pub fn without_haptics(mut self) -> Self { + self.haptic = false; + self + } + pub fn enable_if(&mut self, ctx: &mut EventCtx, enabled: bool) { if enabled { self.enable(ctx); @@ -116,10 +137,9 @@ impl Button { matches!(self.state, State::Disabled) } - pub fn set_content(&mut self, ctx: &mut EventCtx, content: ButtonContent) { + pub fn set_content(&mut self, content: ButtonContent) { if self.content != content { - self.content = content; - ctx.request_paint(); + self.content = content } } @@ -154,34 +174,29 @@ impl Button { } pub fn paint_background(&self, style: &ButtonStyle) { - match &self.content { - ButtonContent::IconBlend(_, _, _) => {} - _ => { - if style.border_width > 0 { - // Paint the border and a smaller background on top of it. - display::rect_fill_rounded( - self.area, - style.border_color, - style.background_color, - style.border_radius, - ); - display::rect_fill_rounded( - self.area.inset(Insets::uniform(style.border_width)), - style.button_color, - style.border_color, - style.border_radius, - ); - } else { - // We do not need to draw an explicit border in this case, just a - // bigger background. - display::rect_fill_rounded( - self.area, - style.button_color, - style.background_color, - style.border_radius, - ); - } - } + display::rect_fill(self.area, style.button_color); + } + + pub fn render_background<'s>( + &self, + target: &mut impl Renderer<'s>, + style: &ButtonStyle, + alpha: u8, + ) { + if self.radius.is_some() { + shape::Bar::new(self.area) + .with_bg(style.background_color) + .with_radius(self.radius.unwrap() as i16) + .with_thickness(2) + .with_fg(style.button_color) + .with_alpha(alpha) + .render(target); + } else { + shape::Bar::new(self.area) + .with_bg(style.button_color) + .with_fg(style.button_color) + .with_alpha(alpha) + .render(target); } } @@ -189,11 +204,7 @@ impl Button { match &self.content { ButtonContent::Empty => {} ButtonContent::Text(text) => { - let width = text.map(|c| style.font.text_width(c)); - let height = style.font.text_height(); - let start_of_baseline = self.area.center() - + Offset::new(-width / 2, height / 2) - + Offset::y(Self::BASELINE_OFFSET); + let start_of_baseline = self.area.center() + Self::BASELINE_OFFSET; text.map(|text| { display::text_left( start_of_baseline, @@ -208,21 +219,66 @@ impl Button { icon.draw( self.area.center(), Alignment2D::CENTER, - style.text_color, + style.icon_color, style.button_color, ); } ButtonContent::IconAndText(child) => { child.paint(self.area, self.style(), Self::BASELINE_OFFSET); } - ButtonContent::IconBlend(bg, fg, offset) => display::icon_over_icon( - Some(self.area), - (*bg, Offset::zero(), style.button_color), - (*fg, *offset, style.text_color), - style.background_color, - ), } } + + pub fn render_content<'s>( + &self, + target: &mut impl Renderer<'s>, + style: &ButtonStyle, + alpha: u8, + ) { + match &self.content { + ButtonContent::Empty => {} + ButtonContent::Text(text) => { + let y_offset = Offset::y(self.style().font.allcase_text_height() / 2); + let start_of_baseline = match self.text_align { + Alignment::Start => { + self.area.left_center() + Offset::x(Self::BASELINE_OFFSET.x) + } + Alignment::Center => self.area.center(), + Alignment::End => self.area.right_center() - Offset::x(Self::BASELINE_OFFSET.x), + } + y_offset; + text.map(|text| { + shape::Text::new(start_of_baseline, text) + .with_font(style.font) + .with_fg(style.text_color) + .with_align(self.text_align) + .with_alpha(alpha) + .render(target); + }); + } + ButtonContent::Icon(icon) => { + shape::ToifImage::new(self.area.center(), icon.toif) + .with_align(Alignment2D::CENTER) + .with_fg(style.icon_color) + .with_alpha(alpha) + .render(target); + } + ButtonContent::IconAndText(child) => { + child.render( + target, + self.area, + self.style(), + Self::BASELINE_OFFSET, + alpha, + ); + } + } + } + + pub fn render_with_alpha<'s>(&self, target: &mut impl Renderer<'s>, alpha: u8) { + let style = self.style(); + self.render_background(target, style, alpha); + self.render_content(target, style, alpha); + } } impl Component for Button { @@ -250,7 +306,9 @@ impl Component for Button { // Touch started in our area, transform to `Pressed` state. if touch_area.contains(pos) { #[cfg(feature = "haptic")] - play(HapticEffect::ButtonPress); + if self.haptic { + play(HapticEffect::ButtonPress); + } self.set(ctx, State::Pressed); if let Some(duration) = self.long_press { self.long_timer = Some(ctx.request_timer(duration)); @@ -282,6 +340,12 @@ impl Component for Button { self.set(ctx, State::Initial); return Some(ButtonMsg::Clicked); } + State::Pressed => { + // Touch finished outside our area. + self.set(ctx, State::Initial); + self.long_timer = None; + return Some(ButtonMsg::Released); + } _ => { // Touch finished outside our area. self.set(ctx, State::Initial); @@ -289,12 +353,33 @@ impl Component for Button { } } } + Event::Touch(TouchEvent::TouchAbort) => { + match self.state { + State::Initial | State::Disabled => { + // Do nothing. + } + State::Pressed => { + // Touch aborted + self.set(ctx, State::Initial); + self.long_timer = None; + return Some(ButtonMsg::Released); + } + _ => { + // Irrelevant touch abort + self.set(ctx, State::Initial); + self.long_timer = None; + } + } + } + Event::Timer(token) => { if self.long_timer == Some(token) { self.long_timer = None; if matches!(self.state, State::Pressed) { #[cfg(feature = "haptic")] - play(HapticEffect::ButtonPress); + if self.haptic { + play(HapticEffect::ButtonPress); + } self.set(ctx, State::Initial); return Some(ButtonMsg::LongPressed); } @@ -311,9 +396,10 @@ impl Component for Button { self.paint_content(style); } - #[cfg(feature = "ui_bounds")] - fn bounds(&self, sink: &mut dyn FnMut(Rect)) { - sink(self.area); + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let style = self.style(); + self.render_background(target, style, 0xFF); + self.render_content(target, style, 0xFF); } } @@ -326,15 +412,14 @@ impl crate::trace::Trace for Button { ButtonContent::Text(text) => t.string("text", *text), ButtonContent::Icon(_) => t.bool("icon", true), ButtonContent::IconAndText(content) => { - t.string("text", content.text.into()); + t.string("text", content.text); t.bool("icon", true); } - ButtonContent::IconBlend(_, _, _) => t.bool("icon", true), } } } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone)] enum State { Initial, Pressed, @@ -342,13 +427,12 @@ enum State { Disabled, } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone)] pub enum ButtonContent { Empty, Text(TString<'static>), Icon(Icon), IconAndText(IconText), - IconBlend(Icon, Icon, Offset), } #[derive(PartialEq, Eq, Clone, Copy)] @@ -363,22 +447,13 @@ pub struct ButtonStyle { pub font: Font, pub text_color: Color, pub button_color: Color, + pub icon_color: Color, pub background_color: Color, - pub border_color: Color, - pub border_radius: u8, - pub border_width: i16, -} - -#[derive(Clone, Copy)] -pub enum CancelInfoConfirmMsg { - Cancelled, - Info, - Confirmed, } -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone)] pub struct IconText { - text: &'static str, + text: TString<'static>, icon: Icon, } @@ -387,12 +462,15 @@ impl IconText { const ICON_MARGIN: i16 = 4; const TEXT_MARGIN: i16 = 6; - pub fn new(text: &'static str, icon: Icon) -> Self { - Self { text, icon } + pub fn new(text: impl Into>, icon: Icon) -> Self { + Self { + text: text.into(), + icon, + } } - pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: i16) { - let width = style.font.text_width(self.text); + pub fn paint(&self, area: Rect, style: &ButtonStyle, baseline_offset: Offset) { + let width = self.text.map(|t| style.font.text_width(t)); let height = style.font.text_height(); let mut use_icon = false; @@ -402,8 +480,7 @@ impl IconText { area.top_left().x + ((Self::ICON_SPACE + Self::ICON_MARGIN) / 2), area.center().y, ); - let mut text_pos = - area.center() + Offset::new(-width / 2, height / 2) + Offset::y(baseline_offset); + let mut text_pos = area.center() + Offset::new(-width / 2, height / 2) + baseline_offset; if area.width() > (Self::ICON_SPACE + Self::TEXT_MARGIN + width) { //display both icon and text @@ -419,22 +496,74 @@ impl IconText { } if use_text { - display::text_left( - text_pos, - self.text, - style.font, - style.text_color, - style.button_color, - ); + self.text.map(|t| { + display::text_left( + text_pos, + t, + style.font, + style.text_color, + style.button_color, + ) + }); } if use_icon { self.icon.draw( icon_pos, Alignment2D::CENTER, - style.text_color, + style.icon_color, style.button_color, ); } } + pub fn render<'s>( + &self, + target: &mut impl Renderer<'s>, + area: Rect, + style: &ButtonStyle, + baseline_offset: Offset, + alpha: u8, + ) { + let width = self.text.map(|t| style.font.text_width(t)); + + let mut use_icon = false; + let mut use_text = false; + + let mut icon_pos = Point::new( + area.top_left().x + ((Self::ICON_SPACE + Self::ICON_MARGIN) / 2), + area.center().y, + ); + let mut text_pos = area.left_center() + baseline_offset; + + if area.width() > (Self::ICON_SPACE + Self::TEXT_MARGIN + width) { + //display both icon and text + text_pos = Point::new(area.top_left().x + Self::ICON_SPACE, text_pos.y); + use_text = true; + use_icon = true; + } else if area.width() > (width + Self::TEXT_MARGIN) { + use_text = true; + } else { + //if we can't fit the text, retreat to centering the icon + icon_pos = area.center(); + use_icon = true; + } + + if use_text { + self.text.map(|t| { + shape::Text::new(text_pos, t) + .with_font(style.font) + .with_fg(style.text_color) + .with_alpha(alpha) + .render(target) + }); + } + + if use_icon { + shape::ToifImage::new(icon_pos, self.icon.toif) + .with_align(Alignment2D::CENTER) + .with_fg(style.icon_color) + .with_alpha(alpha) + .render(target); + } + } } diff --git a/core/embed/rust/src/ui/model_mercury/component/choose_credential.rs b/core/embed/rust/src/ui/model_mercury/component/choose_credential.rs new file mode 100644 index 0000000000..43cc6b4bf3 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/choose_credential.rs @@ -0,0 +1,101 @@ +use crate::{ + strutil::TString, + translations::TR, + ui::{ + component::{swipe_detect::SwipeSettings, Component, SwipeDirection}, + flow::{Swipable, SwipePage}, + }, +}; + +use super::{ + Frame, FrameMsg, InternallySwipable as _, PagedVerticalMenu, SwipeContent, + VerticalMenuChoiceMsg, +}; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum ConfirmFido { + Intro, + ChooseCredential, + Details, + Tap, + Menu, +} + +/// Wrapper that updates `Footer` content whenever page is changed. +pub struct ChooseCredential TString<'static>>( + Frame>>>, +); + +impl TString<'static>> ChooseCredential { + pub fn new(label_fn: F, num_accounts: usize) -> Self { + let content_choose_credential = Frame::left_aligned( + TR::fido__title_select_credential.into(), + SwipeContent::new(SwipePage::vertical(PagedVerticalMenu::new( + num_accounts, + label_fn, + ))), + ) + .with_subtitle(TR::fido__title_for_authentication.into()) + .with_menu_button() + .with_footer_page_hint( + TR::fido__more_credentials.into(), + TR::buttons__go_back.into(), + TR::instructions__swipe_up.into(), + TR::instructions__swipe_down.into(), + ) + .with_swipe(SwipeDirection::Down, SwipeSettings::default()) + .with_swipe(SwipeDirection::Right, SwipeSettings::immediate()) + .with_vertical_pages(); + + Self(content_choose_credential) + } +} + +impl TString<'static>> Component for ChooseCredential { + type Msg = FrameMsg; + + fn place(&mut self, bounds: crate::ui::geometry::Rect) -> crate::ui::geometry::Rect { + self.0.place(bounds) + } + + fn event( + &mut self, + ctx: &mut crate::ui::component::EventCtx, + event: crate::ui::component::Event, + ) -> Option { + let msg = self.0.event(ctx, event); + let current_page = self.0.inner().inner().inner().current_page(); + + self.0.update_footer_counter( + ctx, + current_page, + Some(self.0.inner().inner().inner().num_pages()), + ); + msg + } + + fn paint(&mut self) { + self.0.paint() + } + + fn render<'s>(&'s self, target: &mut impl crate::ui::shape::Renderer<'s>) { + self.0.render(target) + } +} + +impl TString<'static>> Swipable for ChooseCredential { + fn get_swipe_config(&self) -> crate::ui::component::swipe_detect::SwipeConfig { + self.0.get_swipe_config() + } + + fn get_internal_page_count(&self) -> usize { + self.0.get_internal_page_count() + } +} + +#[cfg(feature = "ui_debug")] +impl TString<'static>> crate::trace::Trace for ChooseCredential { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + self.0.trace(t) + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/coinjoin_progress.rs b/core/embed/rust/src/ui/model_mercury/component/coinjoin_progress.rs new file mode 100644 index 0000000000..bdca56291a --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/coinjoin_progress.rs @@ -0,0 +1,169 @@ +use core::mem; + +use crate::{ + error::Error, + maybe_trace::MaybeTrace, + strutil::TString, + translations::TR, + ui::{ + component::{base::Never, Bar, Component, Empty, Event, EventCtx, Label, Split}, + display::loader::{loader_circular_uncompress, LoaderDimensions}, + geometry::{Insets, Offset, Rect}, + model_mercury::constant, + shape, + shape::Renderer, + util::animation_disabled, + }, +}; + +use super::{theme, Frame}; + +const RECTANGLE_HEIGHT: i16 = 56; +const LABEL_TOP: i16 = 135; +const LOADER_OUTER: i16 = 39; +const LOADER_INNER: i16 = 28; +const LOADER_OFFSET: i16 = -34; +const LOADER_SPEED: u16 = 5; + +pub struct CoinJoinProgress { + value: u16, + indeterminate: bool, + content: Frame>, + // Label is not a child since circular loader paints large black rectangle which overlaps it. + // To work around this, draw label every time loader is drawn. + label: Label<'static>, +} + +impl CoinJoinProgress { + pub fn new( + text: TString<'static>, + indeterminate: bool, + ) -> Result + MaybeTrace>, Error> { + let style = theme::label_coinjoin_progress(); + let label = Label::centered(TR::coinjoin__title_do_not_disconnect.into(), style) + .vertically_centered(); + let bg = Bar::new(style.background_color, theme::BG, 2); + let inner = (bg, label); + CoinJoinProgress::with_background(text, inner, indeterminate) + } +} + +impl CoinJoinProgress +where + U: Component, +{ + pub fn with_background( + text: TString<'static>, + inner: U, + indeterminate: bool, + ) -> Result { + Ok(Self { + value: 0, + indeterminate, + content: Frame::centered( + TR::coinjoin__title_progress.into(), + Split::bottom(RECTANGLE_HEIGHT, 0, Empty, inner), + ), + label: Label::centered(text, theme::TEXT_NORMAL), + }) + } +} + +impl Component for CoinJoinProgress +where + U: Component, +{ + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + self.content.place(bounds); + let label_bounds = bounds.inset(Insets::top(LABEL_TOP)); + self.label.place(label_bounds); + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + self.content.event(ctx, event); + self.label.event(ctx, event); + match event { + _ if animation_disabled() => { + return None; + } + Event::Attach(_) if self.indeterminate => { + ctx.request_anim_frame(); + } + Event::Timer(EventCtx::ANIM_FRAME_TIMER) => { + self.value = (self.value + LOADER_SPEED) % 1000; + ctx.request_anim_frame(); + ctx.request_paint(); + } + Event::Progress(new_value, _new_description) => { + if mem::replace(&mut self.value, new_value) != new_value { + ctx.request_paint(); + } + } + _ => {} + } + None + } + + fn paint(&mut self) { + self.content.paint(); + loader_circular_uncompress( + LoaderDimensions::new(LOADER_OUTER, LOADER_INNER), + LOADER_OFFSET, + theme::FG, + theme::BG, + self.value, + self.indeterminate, + None, + ); + self.label.paint(); + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.content.render(target); + + let center = constant::screen().center() + Offset::y(LOADER_OFFSET); + let active_color = theme::FG; + let background_color = theme::BG; + let inactive_color = background_color.blend(active_color, 85); + + let start = (self.value as i16 - 100) % 1000; + let end = (self.value as i16 + 100) % 1000; + let start = 360.0 * start as f32 / 1000.0; + let end = 360.0 * end as f32 / 1000.0; + + shape::Circle::new(center, LOADER_OUTER) + .with_bg(inactive_color) + .render(target); + + shape::Circle::new(center, LOADER_OUTER) + .with_bg(active_color) + .with_start_angle(start) + .with_end_angle(end) + .render(target); + + shape::Circle::new(center, LOADER_INNER + 2) + .with_bg(active_color) + .render(target); + + shape::Circle::new(center, LOADER_INNER) + .with_bg(background_color) + .render(target); + + self.label.render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for CoinJoinProgress +where + U: Component + crate::trace::Trace, +{ + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("CoinJoinProgress"); + t.child("label", &self.label); + t.child("content", &self.content); + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/error.rs b/core/embed/rust/src/ui/model_mercury/component/error.rs index 7e046d722a..9df9741851 100644 --- a/core/embed/rust/src/ui/model_mercury/component/error.rs +++ b/core/embed/rust/src/ui/model_mercury/component/error.rs @@ -1,9 +1,11 @@ use crate::{ strutil::TString, ui::{ - component::{Child, Component, Event, EventCtx, Label, Never, Pad}, + component::{Component, Event, EventCtx, Label, Never, Pad}, constant::screen, geometry::{Alignment2D, Point, Rect}, + shape, + shape::Renderer, }, }; @@ -15,7 +17,7 @@ use super::{ const ICON_TOP: i16 = 23; const TITLE_AREA_START: i16 = 70; -const MESSAGE_AREA_START: i16 = 116; +const MESSAGE_AREA_START: i16 = 90; #[cfg(feature = "bootloader")] const STYLE: &ResultStyle = &crate::ui::model_mercury::theme::bootloader::RESULT_WIPE; @@ -24,15 +26,15 @@ const STYLE: &ResultStyle = &super::theme::RESULT_ERROR; pub struct ErrorScreen<'a> { bg: Pad, - title: Child>, - message: Child>, - footer: Child>, + title: Label<'a>, + message: Label<'a>, + footer: ResultFooter<'a>, } impl<'a> ErrorScreen<'a> { pub fn new(title: TString<'a>, message: TString<'a>, footer: TString<'a>) -> Self { let title = Label::centered(title, STYLE.title_style()); - let message = Label::centered(message, STYLE.message_style()); + let message = Label::centered(message, STYLE.message_style()).vertically_centered(); let footer = ResultFooter::new( Label::centered(footer, STYLE.title_style()).vertically_centered(), STYLE, @@ -40,9 +42,9 @@ impl<'a> ErrorScreen<'a> { Self { bg: Pad::with_background(FATAL_ERROR_COLOR).with_clear(), - title: Child::new(title), - message: Child::new(message), - footer: Child::new(footer), + title, + message, + footer, } } } @@ -89,4 +91,19 @@ impl<'a> Component for ErrorScreen<'a> { self.message.paint(); self.footer.paint(); } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.bg.render(target); + + let icon = ICON_WARNING40; + shape::ToifImage::new(Point::new(screen().center().x, ICON_TOP), icon.toif) + .with_fg(WHITE) + .with_bg(FATAL_ERROR_COLOR) + .with_align(Alignment2D::TOP_CENTER) + .render(target); + + self.title.render(target); + self.message.render(target); + self.footer.render(target); + } } diff --git a/core/embed/rust/src/ui/model_mercury/component/fido.rs b/core/embed/rust/src/ui/model_mercury/component/fido.rs new file mode 100644 index 0000000000..92bcbe344e --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/fido.rs @@ -0,0 +1,88 @@ +use crate::{ + strutil::TString, + ui::{ + component::{ + image::Image, + text::paragraphs::{Paragraph, ParagraphSource, ParagraphVecShort, Paragraphs}, + Component, Event, EventCtx, + }, + geometry::{Insets, Offset, Rect}, + model_mercury::component::{fido_icons::get_fido_icon_data, theme}, + shape::Renderer, + }, +}; + +pub struct FidoCredential TString<'static>> { + app_icon: Option, + text: Paragraphs>, + get_account: F, +} + +impl TString<'static>> FidoCredential { + const ICON_SIZE: i16 = 32; + const SPACING: i16 = 8; + + pub fn new( + icon_name: Option>, + app_name: TString<'static>, + get_account: F, + ) -> Self { + let app_icon = get_fido_icon_data(icon_name).map(Image::new); + let text = ParagraphVecShort::from_iter([ + Paragraph::new(&theme::TEXT_SUB_GREY, app_name), + Paragraph::new(&theme::TEXT_MAIN_GREY_EXTRA_LIGHT, (get_account)()), + ]) + .into_paragraphs(); + Self { + app_icon, + text, + get_account, + } + } +} + +impl TString<'static>> Component for FidoCredential { + type Msg = (); + + fn place(&mut self, bounds: Rect) -> Rect { + let icon_size = self.app_icon.map_or(Offset::zero(), |i| i.toif.size()); + let (icon_area, text_area) = bounds.split_top(icon_size.y); + let text_area = text_area.inset(Insets::top(Self::SPACING)); + self.text.place(text_area); + let text_height = self.text.area().height(); + let vertical_space = bounds.height() - icon_size.y - Self::SPACING - text_height; + let off = Offset::y(vertical_space / 2); + + let icon_area = icon_area.with_width(icon_size.x).translate(off); + let text_area = text_area.with_height(text_height).translate(off); + self.app_icon.place(icon_area); + self.text.place(text_area); + bounds + } + + fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { + if let Event::Attach(_) = event { + self.text.inner_mut()[1].update((self.get_account)()); + ctx.request_paint(); + } + self.app_icon.event(ctx, event); + self.text.event(ctx, event); + None + } + + fn paint(&mut self) { + unimplemented!() + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.app_icon.render(target); + self.text.render(target); + } +} + +#[cfg(feature = "ui_debug")] +impl TString<'static>> crate::trace::Trace for FidoCredential { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("FidoCredential"); + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs b/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs new file mode 100644 index 0000000000..77eeabfbe1 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs @@ -0,0 +1,80 @@ +//! generated from webauthn_icons.rs.mako +//! (by running `make templates` in `core`) +//! do not edit manually! + + +use crate::strutil::TString; +use crate::ui::util::include_res; + + +const ICON_APPLE: &[u8] = include_res!("model_mercury/res/fido/icon_apple.toif"); +const ICON_AWS: &[u8] = include_res!("model_mercury/res/fido/icon_aws.toif"); +const ICON_BINANCE: &[u8] = include_res!("model_mercury/res/fido/icon_binance.toif"); +const ICON_BITBUCKET: &[u8] = include_res!("model_mercury/res/fido/icon_bitbucket.toif"); +const ICON_BITFINEX: &[u8] = include_res!("model_mercury/res/fido/icon_bitfinex.toif"); +const ICON_BITWARDEN: &[u8] = include_res!("model_mercury/res/fido/icon_bitwarden.toif"); +const ICON_CLOUDFLARE: &[u8] = include_res!("model_mercury/res/fido/icon_cloudflare.toif"); +const ICON_COINBASE: &[u8] = include_res!("model_mercury/res/fido/icon_coinbase.toif"); +const ICON_DASHLANE: &[u8] = include_res!("model_mercury/res/fido/icon_dashlane.toif"); +const ICON_DROPBOX: &[u8] = include_res!("model_mercury/res/fido/icon_dropbox.toif"); +const ICON_DUO: &[u8] = include_res!("model_mercury/res/fido/icon_duo.toif"); +const ICON_FACEBOOK: &[u8] = include_res!("model_mercury/res/fido/icon_facebook.toif"); +const ICON_FASTMAIL: &[u8] = include_res!("model_mercury/res/fido/icon_fastmail.toif"); +const ICON_FEDORA: &[u8] = include_res!("model_mercury/res/fido/icon_fedora.toif"); +const ICON_GANDI: &[u8] = include_res!("model_mercury/res/fido/icon_gandi.toif"); +const ICON_GEMINI: &[u8] = include_res!("model_mercury/res/fido/icon_gemini.toif"); +const ICON_GITHUB: &[u8] = include_res!("model_mercury/res/fido/icon_github.toif"); +const ICON_GITLAB: &[u8] = include_res!("model_mercury/res/fido/icon_gitlab.toif"); +const ICON_GOOGLE: &[u8] = include_res!("model_mercury/res/fido/icon_google.toif"); +const ICON_INVITY: &[u8] = include_res!("model_mercury/res/fido/icon_invity.toif"); +const ICON_KEEPER: &[u8] = include_res!("model_mercury/res/fido/icon_keeper.toif"); +const ICON_KRAKEN: &[u8] = include_res!("model_mercury/res/fido/icon_kraken.toif"); +const ICON_LOGIN_GOV: &[u8] = include_res!("model_mercury/res/fido/icon_login.gov.toif"); +const ICON_MICROSOFT: &[u8] = include_res!("model_mercury/res/fido/icon_microsoft.toif"); +const ICON_MOJEID: &[u8] = include_res!("model_mercury/res/fido/icon_mojeid.toif"); +const ICON_NAMECHEAP: &[u8] = include_res!("model_mercury/res/fido/icon_namecheap.toif"); +const ICON_PROTON: &[u8] = include_res!("model_mercury/res/fido/icon_proton.toif"); +const ICON_SLUSHPOOL: &[u8] = include_res!("model_mercury/res/fido/icon_slushpool.toif"); +const ICON_STRIPE: &[u8] = include_res!("model_mercury/res/fido/icon_stripe.toif"); +const ICON_TUTANOTA: &[u8] = include_res!("model_mercury/res/fido/icon_tutanota.toif"); + +/// Translates icon name into its data. +pub fn get_fido_icon_data(icon_name: Option>) -> Option< &'static [u8]> { + if let Some(icon_name) = icon_name { + icon_name.map(|c| match c { + "apple" => Some(ICON_APPLE), + "aws" => Some(ICON_AWS), + "binance" => Some(ICON_BINANCE), + "bitbucket" => Some(ICON_BITBUCKET), + "bitfinex" => Some(ICON_BITFINEX), + "bitwarden" => Some(ICON_BITWARDEN), + "cloudflare" => Some(ICON_CLOUDFLARE), + "coinbase" => Some(ICON_COINBASE), + "dashlane" => Some(ICON_DASHLANE), + "dropbox" => Some(ICON_DROPBOX), + "duo" => Some(ICON_DUO), + "facebook" => Some(ICON_FACEBOOK), + "fastmail" => Some(ICON_FASTMAIL), + "fedora" => Some(ICON_FEDORA), + "gandi" => Some(ICON_GANDI), + "gemini" => Some(ICON_GEMINI), + "github" => Some(ICON_GITHUB), + "gitlab" => Some(ICON_GITLAB), + "google" => Some(ICON_GOOGLE), + "invity" => Some(ICON_INVITY), + "keeper" => Some(ICON_KEEPER), + "kraken" => Some(ICON_KRAKEN), + "login.gov" => Some(ICON_LOGIN_GOV), + "microsoft" => Some(ICON_MICROSOFT), + "mojeid" => Some(ICON_MOJEID), + "namecheap" => Some(ICON_NAMECHEAP), + "proton" => Some(ICON_PROTON), + "slushpool" => Some(ICON_SLUSHPOOL), + "stripe" => Some(ICON_STRIPE), + "tutanota" => Some(ICON_TUTANOTA), + _ => None, + }) + } else { + None + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs.mako b/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs.mako new file mode 100644 index 0000000000..3aeb2c92b0 --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/fido_icons.rs.mako @@ -0,0 +1,35 @@ +//! generated from webauthn_icons.rs.mako +//! (by running `make templates` in `core`) +//! do not edit manually! + + +use crate::strutil::TString; +use crate::ui::util::include_res; + +<% +icons: list[tuple[str, str]] = [] +for app in fido: + if app.icon is not None: + # Variable names cannot have a dot in themselves + icon_name = app.key + var_name = icon_name.replace(".", "_").upper() + icons.append((icon_name, var_name)) +%>\ + +% for icon_name, var_name in icons: +const ICON_${var_name}: &[u8] = include_res!("model_mercury/res/fido/icon_${icon_name}.toif"); +% endfor + +/// Translates icon name into its data. +pub fn get_fido_icon_data(icon_name: Option>) -> Option< &'static [u8]> { + if let Some(icon_name) = icon_name { + icon_name.map(|c| match c { +% for icon_name, var_name in icons: + "${icon_name}" => Some(ICON_${var_name}), +% endfor + _ => None, + }) + } else { + None + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/footer.rs b/core/embed/rust/src/ui/model_mercury/component/footer.rs new file mode 100644 index 0000000000..fd5836027a --- /dev/null +++ b/core/embed/rust/src/ui/model_mercury/component/footer.rs @@ -0,0 +1,463 @@ +use crate::{ + strutil::TString, + ui::{ + component::{text::TextStyle, Component, Event, EventCtx, Never, SwipeDirection}, + display::{Color, Font}, + event::SwipeEvent, + geometry::{Alignment, Alignment2D, Offset, Point, Rect}, + lerp::Lerp, + model_mercury::theme, + shape, + shape::{Renderer, Text}, + }, +}; + +/// Component showing a task instruction, e.g. "Swipe up", and an optional +/// content consisting of one of these: +/// - a task description e.g. "Confirm transaction", or +/// - a page counter e.g. "1 / 3", meaning the first screen of three total. +/// A host of this component is responsible of providing the exact area +/// considering also the spacing. The height must be 18px (only instruction) or +/// 37px (instruction and description/position). +#[derive(Clone)] +pub struct Footer<'a> { + area: Rect, + content: FooterContent<'a>, + swipe_allow_up: bool, + swipe_allow_down: bool, + progress: i16, + dir: SwipeDirection, +} + +#[derive(Clone)] +enum FooterContent<'a> { + Instruction(TString<'a>), + InstructionDescription(TString<'a>, TString<'a>), + PageCounter(PageCounter), + PageHint(PageHint), +} + +impl<'a> Footer<'a> { + /// height of the component with only instruction [px] + pub const HEIGHT_SIMPLE: i16 = 18; + /// height of the component with instruction and additional content [px] + pub const HEIGHT_DEFAULT: i16 = 37; + + const STYLE_INSTRUCTION: &'static TextStyle = &theme::TEXT_SUB_GREY; + const STYLE_DESCRIPTION: &'static TextStyle = &theme::TEXT_SUB_GREY_LIGHT; + + fn from_content(content: FooterContent<'a>) -> Self { + Self { + area: Rect::zero(), + content, + swipe_allow_down: false, + swipe_allow_up: false, + progress: 0, + dir: SwipeDirection::Up, + } + } + + pub fn new>>( + instruction: T, + description: Option>, + ) -> Self { + let instruction = instruction.into(); + Self::from_content( + description + .map(|d| FooterContent::InstructionDescription(instruction, d)) + .unwrap_or(FooterContent::Instruction(instruction)), + ) + } + + pub fn with_page_counter(max_pages: u8, instruction: TString<'static>) -> Self { + Self::from_content(FooterContent::PageCounter(PageCounter::new( + max_pages, + instruction, + ))) + } + + pub fn with_page_hint( + description: TString<'static>, + description_last: TString<'static>, + instruction: TString<'static>, + instruction_last: TString<'static>, + ) -> Self { + Self::from_content(FooterContent::PageHint(PageHint { + description, + description_last, + instruction, + instruction_last, + page_curr: 0, + page_num: 1, + })) + } + + pub fn update_instruction>>(&mut self, ctx: &mut EventCtx, s: T) { + match &mut self.content { + FooterContent::Instruction(i) => *i = s.into(), + FooterContent::InstructionDescription(i, _d) => *i = s.into(), + FooterContent::PageCounter(page_counter) => page_counter.instruction = s.into(), + _ => { + #[cfg(feature = "ui_debug")] + panic!("not supported") + } + } + ctx.request_paint(); + } + + pub fn update_description>>(&mut self, ctx: &mut EventCtx, s: T) { + if let FooterContent::InstructionDescription(_i, d) = &mut self.content { + *d = s.into(); + ctx.request_paint(); + } else { + #[cfg(feature = "ui_debug")] + panic!("footer does not have description") + } + } + + pub fn update_page_counter(&mut self, ctx: &mut EventCtx, current: usize, max: Option) { + match &mut self.content { + FooterContent::PageCounter(counter) => { + counter.update_current_page(current); + self.swipe_allow_down = counter.is_first_page(); + self.swipe_allow_up = counter.is_last_page(); + ctx.request_paint(); + } + FooterContent::PageHint(page_hint) => { + page_hint.update_current_page(current, max); + self.swipe_allow_down = page_hint.is_first_page(); + self.swipe_allow_up = page_hint.is_last_page(); + ctx.request_paint(); + } + _ => { + #[cfg(feature = "ui_debug")] + panic!("footer does not have counter") + } + } + } + + pub fn height(&self) -> i16 { + self.content.height() + } + + pub fn with_swipe(self, swipe_direction: SwipeDirection) -> Self { + match swipe_direction { + SwipeDirection::Up => Self { + swipe_allow_up: true, + ..self + }, + SwipeDirection::Down => Self { + swipe_allow_down: true, + ..self + }, + _ => self, + } + } +} + +impl<'a> Component for Footer<'a> { + type Msg = Never; + + fn place(&mut self, bounds: Rect) -> Rect { + assert!(bounds.height() == self.content.height()); + self.area = bounds; + self.area + } + + fn event(&mut self, _ctx: &mut EventCtx, event: Event) -> Option { + match event { + Event::Attach(_) => { + self.progress = 0; + } + Event::Swipe(SwipeEvent::Move(dir, progress)) => match dir { + SwipeDirection::Up => { + if self.swipe_allow_up { + self.progress = progress; + self.dir = dir; + } + } + SwipeDirection::Down => { + if self.swipe_allow_down { + self.progress = progress; + self.dir = dir; + } + } + _ => {} + }, + _ => {} + }; + + None + } + + fn paint(&mut self) { + todo!("remove when ui-t3t1 done") + } + + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + let progress = self.progress as f32 / 1000.0; + + let shift = pareen::constant(0.0).seq_ease_out( + 0.0, + easer::functions::Cubic, + 1.0, + pareen::constant(1.0), + ); + + let offset = i16::lerp(0, 20, shift.eval(progress)); + + let mask = u8::lerp(0, 255, shift.eval(progress)); + + let offset = match self.dir { + SwipeDirection::Up => Offset::y(-offset), + SwipeDirection::Down => Offset::y(3 * offset), + _ => Offset::zero(), + }; + + target.with_origin(offset, &|target| { + self.content.render(self.area, target); + shape::Bar::new(self.area) + .with_alpha(mask) + .with_fg(Color::black()) + .with_bg(Color::black()) + .render(target); + }); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for Footer<'_> { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("Footer"); + match &self.content { + FooterContent::Instruction(i) => { + t.string("instruction", *i); + } + FooterContent::InstructionDescription(i, d) => { + t.string("description", *d); + t.string("instruction", *i); + } + FooterContent::PageCounter(counter) => counter.trace(t), + FooterContent::PageHint(page_hint) => { + t.string("description", page_hint.description()); + t.string("instruction", page_hint.instruction()); + } + } + } +} + +impl<'a> FooterContent<'a> { + fn height(&self) -> i16 { + if matches!(self, FooterContent::Instruction(_)) { + Footer::HEIGHT_SIMPLE + } else { + Footer::HEIGHT_DEFAULT + } + } + + fn render<'s>(&'s self, area: Rect, target: &mut impl Renderer<'s>) + where + 's: 'a, + { + match self { + FooterContent::Instruction(instruction) => { + Self::render_instruction(target, area, instruction); + } + FooterContent::InstructionDescription(instruction, description) => { + Self::render_description(target, area, description); + Self::render_instruction(target, area, instruction); + } + FooterContent::PageCounter(page_counter) => page_counter.render(target, area), + FooterContent::PageHint(page_hint) => { + Self::render_description(target, area, &page_hint.description()); + Self::render_instruction(target, area, &page_hint.instruction()); + } + } + } + + fn render_description<'s>( + target: &mut impl Renderer<'s>, + area: Rect, + description: &TString<'a>, + ) { + let area_description = area.split_top(Footer::HEIGHT_SIMPLE).0; + let text_description_font_descent = Footer::STYLE_DESCRIPTION + .text_font + .visible_text_height_ex("Ay") + .1; + let text_description_baseline = + area_description.bottom_center() - Offset::y(text_description_font_descent); + + description.map(|t| { + Text::new(text_description_baseline, t) + .with_font(Footer::STYLE_DESCRIPTION.text_font) + .with_fg(Footer::STYLE_DESCRIPTION.text_color) + .with_align(Alignment::Center) + .render(target) + }); + } + + fn render_instruction<'s>( + target: &mut impl Renderer<'s>, + area: Rect, + instruction: &TString<'a>, + ) { + let area_instruction = area.split_bottom(Footer::HEIGHT_SIMPLE).1; + let text_instruction_font_descent = Footer::STYLE_INSTRUCTION + .text_font + .visible_text_height_ex("Ay") + .1; + let text_instruction_baseline = + area_instruction.bottom_center() - Offset::y(text_instruction_font_descent); + instruction.map(|t| { + Text::new(text_instruction_baseline, t) + .with_font(Footer::STYLE_INSTRUCTION.text_font) + .with_fg(Footer::STYLE_INSTRUCTION.text_color) + .with_align(Alignment::Center) + .render(target) + }); + } +} + +/// Helper component used within Footer instead of description for page count +/// indication, rendered e.g. as: '1 / 20'. +#[derive(Clone)] +struct PageCounter { + pub instruction: TString<'static>, + font: Font, + page_curr: u8, + page_max: u8, +} + +impl PageCounter { + fn new(page_max: u8, instruction: TString<'static>) -> Self { + Self { + instruction, + page_curr: 0, + page_max, + font: Font::SUB, + } + } + + fn update_current_page(&mut self, new_value: usize) { + self.page_curr = (new_value as u8).clamp(0, self.page_max.saturating_sub(1)); + } + + fn is_first_page(&self) -> bool { + self.page_curr == 0 + } + + fn is_last_page(&self) -> bool { + self.page_curr + 1 == self.page_max + } +} + +impl PageCounter { + fn render<'s>(&'s self, target: &mut impl Renderer<'s>, area: Rect) { + let color = if self.is_last_page() { + theme::GREEN_LIGHT + } else { + theme::GREY_LIGHT + }; + + let string_curr = uformat!("{}", self.page_curr + 1); + let string_max = uformat!("{}", self.page_max); + + // center the whole counter "x / yz" + let offset_x = Offset::x(4); // spacing between foreslash and numbers + let width_num_curr = self.font.text_width(&string_curr); + let width_foreslash = theme::ICON_FORESLASH.toif.width(); + let width_num_max = self.font.text_width(&string_max); + let width_total = width_num_curr + width_foreslash + width_num_max + 2 * offset_x.x; + + let counter_area = area.split_top(Footer::HEIGHT_SIMPLE).0; + let center_x = counter_area.center().x; + let counter_y = self.font.vert_center(counter_area.y0, counter_area.y1, "0"); + let counter_start_x = center_x - width_total / 2; + let counter_end_x = center_x + width_total / 2; + let base_num_curr = Point::new(counter_start_x, counter_y); + let base_foreslash = Point::new(counter_start_x + width_num_curr + offset_x.x, counter_y); + let base_num_max = Point::new(counter_end_x, counter_y); + + Text::new(base_num_curr, &string_curr) + .with_align(Alignment::Start) + .with_fg(color) + .with_font(self.font) + .render(target); + shape::ToifImage::new(base_foreslash, theme::ICON_FORESLASH.toif) + .with_align(Alignment2D::BOTTOM_LEFT) + .with_fg(color) + .render(target); + Text::new(base_num_max, &string_max) + .with_align(Alignment::End) + .with_fg(color) + .with_font(self.font) + .render(target); + + FooterContent::render_instruction(target, area, &self.instruction); + } +} + +#[cfg(feature = "ui_debug")] +impl crate::trace::Trace for PageCounter { + fn trace(&self, t: &mut dyn crate::trace::Tracer) { + t.component("PageCounter"); + t.int("page current", self.page_curr.into()); + t.int("page max", self.page_max.into()); + } +} + +#[derive(Clone)] +struct PageHint { + pub description: TString<'static>, + pub description_last: TString<'static>, + pub instruction: TString<'static>, + pub instruction_last: TString<'static>, + pub page_curr: u8, + pub page_num: u8, +} + +impl PageHint { + fn update_current_page(&mut self, current: usize, max: Option) { + self.page_curr = (current as u8).clamp(0, self.page_num.saturating_sub(1)); + if let Some(max) = max { + self.page_num = max as u8; + } + } + + fn update_max_page(&mut self, max: usize) { + self.page_num = max as u8; + } + + fn is_single_page(&self) -> bool { + self.page_num <= 1 + } + + fn is_first_page(&self) -> bool { + self.page_curr == 0 + } + + fn is_last_page(&self) -> bool { + self.page_curr + 1 == self.page_num + } + + fn description(&self) -> TString<'static> { + if self.is_single_page() { + TString::empty() + } else if self.is_last_page() { + self.description_last + } else { + self.description + } + } + + fn instruction(&self) -> TString<'static> { + if self.is_single_page() { + TString::empty() + } else if self.is_last_page() { + self.instruction_last + } else { + self.instruction + } + } +} diff --git a/core/embed/rust/src/ui/model_mercury/component/frame.rs b/core/embed/rust/src/ui/model_mercury/component/frame.rs index b29f29fe3d..410c04b94b 100644 --- a/core/embed/rust/src/ui/model_mercury/component/frame.rs +++ b/core/embed/rust/src/ui/model_mercury/component/frame.rs @@ -1,120 +1,282 @@ -use super::theme; +use super::{theme, ButtonStyleSheet, Footer, Header}; use crate::{ strutil::TString, ui::{ component::{ - base::ComponentExt, label::Label, text::TextStyle, Child, Component, Event, EventCtx, + swipe_detect::{SwipeConfig, SwipeSettings}, + text::TextStyle, + Component, + Event::{self, Swipe}, + EventCtx, FlowMsg, SwipeDetect, SwipeDirection, }, - display::Icon, - geometry::{Alignment, Insets, Offset, Rect}, + display::{Color, Icon}, + event::SwipeEvent, + geometry::{Alignment, Insets, Point, Rect}, + lerp::Lerp, + model_mercury::theme::TITLE_HEIGHT, + shape::{self, Renderer}, }, }; -use super::{Button, ButtonMsg, CancelInfoConfirmMsg}; +#[derive(Clone)] +pub struct HorizontalSwipe { + progress: i16, + dir: SwipeDirection, +} + +impl HorizontalSwipe { + const fn new() -> Self { + Self { + progress: 0, + dir: SwipeDirection::Up, + } + } + + fn event(&mut self, event: Event, swipe: SwipeConfig) { + if let Event::Attach(_) = event { + self.progress = 0; + } + + if let Swipe(SwipeEvent::Move(dir, progress)) = event { + if swipe.is_allowed(dir) { + match dir { + SwipeDirection::Left | SwipeDirection::Right => { + self.progress = progress; + self.dir = dir; + } + _ => {} + } + } + } + } + fn render_swipe_cover<'s>(&self, target: &mut impl Renderer<'s>, bounds: Rect) { + if self.progress > 0 { + match self.dir { + SwipeDirection::Left => { + let shift = pareen::constant(0.0).seq_ease_out( + 0.0, + easer::functions::Circ, + 1.0, + pareen::constant(1.0), + ); + + let p = Point::lerp( + bounds.top_right(), + bounds.top_left(), + shift.eval(self.progress as f32 / SwipeDetect::PROGRESS_MAX as f32), + ); + + shape::Bar::new(Rect::new(p, bounds.bottom_right())) + .with_fg(theme::BLACK) + .with_bg(theme::BLACK) + .render(target); + } + SwipeDirection::Right => {} + _ => {} + } + } + } +} + +#[derive(Clone)] pub struct Frame { border: Insets, - title: Child>, - subtitle: Option>>, - button: Option>, - button_msg: CancelInfoConfirmMsg, - content: Child, + bounds: Rect, + content: T, + header: Header, + footer: Option>, + swipe: SwipeConfig, + internal_page_cnt: usize, + horizontal_swipe: HorizontalSwipe, } pub enum FrameMsg { Content(T), - Button(CancelInfoConfirmMsg), + Button(FlowMsg), } impl Frame where T: Component, { - pub fn new( - style: TextStyle, - alignment: Alignment, - title: TString<'static>, - content: T, - ) -> Self { + pub const fn new(alignment: Alignment, title: TString<'static>, content: T) -> Self { Self { - title: Child::new(Label::new(title, alignment, style)), - subtitle: None, + bounds: Rect::zero(), border: theme::borders(), - button: None, - button_msg: CancelInfoConfirmMsg::Cancelled, - content: Child::new(content), + content, + header: Header::new(alignment, title), + footer: None, + swipe: SwipeConfig::new(), + internal_page_cnt: 1, + horizontal_swipe: HorizontalSwipe::new(), } } - pub fn left_aligned(style: TextStyle, title: TString<'static>, content: T) -> Self { - Self::new(style, Alignment::Start, title, content) + #[inline(never)] + pub const fn left_aligned(title: TString<'static>, content: T) -> Self { + Self::new(Alignment::Start, title, content) } - pub fn right_aligned(style: TextStyle, title: TString<'static>, content: T) -> Self { - Self::new(style, Alignment::End, title, content) + #[inline(never)] + pub const fn right_aligned(title: TString<'static>, content: T) -> Self { + Self::new(Alignment::End, title, content) } - pub fn centered(style: TextStyle, title: TString<'static>, content: T) -> Self { - Self::new(style, Alignment::Center, title, content) + #[inline(never)] + pub const fn centered(title: TString<'static>, content: T) -> Self { + Self::new(Alignment::Center, title, content) } - pub fn with_border(mut self, border: Insets) -> Self { + #[inline(never)] + pub const fn with_border(mut self, border: Insets) -> Self { self.border = border; self } - pub fn with_subtitle(mut self, style: TextStyle, subtitle: TString<'static>) -> Self { - self.subtitle = Some(Child::new(Label::new( - subtitle, - self.title.inner().alignment(), - style, - ))); + #[inline(never)] + pub fn with_subtitle(mut self, subtitle: TString<'static>) -> Self { + self.header = self.header.with_subtitle(subtitle); self } - fn with_button(mut self, icon: Icon, msg: CancelInfoConfirmMsg) -> Self { - let touch_area = Insets { - left: self.border.left * 4, - bottom: self.border.bottom * 4, - ..self.border - }; - self.button = Some(Child::new( - Button::with_icon(icon) - .with_expanded_touch_area(touch_area) - .styled(theme::button_moreinfo()), - )); - self.button_msg = msg; + #[inline(never)] + fn with_button(mut self, icon: Icon, msg: FlowMsg, enabled: bool) -> Self { + self.header = self.header.with_button(icon, enabled, msg); self } pub fn with_cancel_button(self) -> Self { - self.with_button(theme::ICON_CORNER_CANCEL, CancelInfoConfirmMsg::Cancelled) + self.with_button(theme::ICON_CLOSE, FlowMsg::Cancelled, true) + } + + pub fn with_menu_button(self) -> Self { + self.with_button(theme::ICON_MENU, FlowMsg::Info, true) + } + + pub fn with_warning_low_icon(self) -> Self { + self.with_button(theme::ICON_WARNING, FlowMsg::Info, false) + .button_styled(theme::button_warning_low()) + } + + pub fn with_danger_icon(self) -> Self { + self.with_button(theme::ICON_WARNING, FlowMsg::Info, false) + .button_styled(theme::button_danger()) + } + + pub fn title_styled(mut self, style: TextStyle) -> Self { + self.header = self.header.styled(style); + self + } + + pub fn subtitle_styled(mut self, style: TextStyle) -> Self { + self.header = self.header.subtitle_styled(style); + self + } + + pub fn button_styled(mut self, style: ButtonStyleSheet) -> Self { + self.header = self.header.button_styled(style); + self + } + + pub fn with_result_icon(mut self, icon: Icon, color: Color) -> Self { + self.header = self.header.with_result_icon(icon, color); + self + } + + #[inline(never)] + pub fn with_footer( + mut self, + instruction: TString<'static>, + description: Option>, + ) -> Self { + self.footer = Some(Footer::new(instruction, description)); + self + } + + #[inline(never)] + pub fn with_footer_counter(mut self, instruction: TString<'static>, max_value: u8) -> Self { + self.footer = Some(Footer::with_page_counter(max_value, instruction)); + self + } + + #[inline(never)] + pub fn with_footer_page_hint( + mut self, + description: TString<'static>, + description_last: TString<'static>, + instruction: TString<'static>, + instruction_last: TString<'static>, + ) -> Self { + self.footer = Some(Footer::with_page_hint( + description, + description_last, + instruction, + instruction_last, + )); + self } - pub fn with_info_button(self) -> Self { - self.with_button(theme::ICON_CORNER_INFO, CancelInfoConfirmMsg::Info) + pub fn with_danger(self) -> Self { + self.button_styled(theme::button_danger()) + .title_styled(theme::label_title_danger()) } pub fn inner(&self) -> &T { - self.content.inner() + &self.content } pub fn update_title(&mut self, ctx: &mut EventCtx, new_title: TString<'static>) { - self.title.mutate(ctx, |ctx, t| { - t.set_text(new_title); - t.request_complete_repaint(ctx) - }) + self.header.update_title(ctx, new_title); + } + + pub fn update_subtitle( + &mut self, + ctx: &mut EventCtx, + new_subtitle: TString<'static>, + new_style: Option, + ) { + self.header.update_subtitle(ctx, new_subtitle, new_style); } pub fn update_content(&mut self, ctx: &mut EventCtx, update_fn: F) -> R where - F: Fn(&mut T) -> R, + F: Fn(&mut EventCtx, &mut T) -> R, { - self.content.mutate(ctx, |ctx, c| { - let res = update_fn(c); - c.request_complete_repaint(ctx); - res - }) + let res = update_fn(ctx, &mut self.content); + ctx.request_paint(); + res + } + + pub fn update_footer_counter( + &mut self, + ctx: &mut EventCtx, + current: usize, + max: Option, + ) { + if let Some(footer) = &mut self.footer { + footer.update_page_counter(ctx, current, max); + } + } + + #[inline(never)] + pub fn with_swipe(mut self, dir: SwipeDirection, settings: SwipeSettings) -> Self { + self.footer = self.footer.map(|f| f.with_swipe(dir)); + self.swipe = self.swipe.with_swipe(dir, settings); + self + } + + pub fn with_horizontal_pages(self) -> Self { + Self { + swipe: self.swipe.with_horizontal_pages(), + ..self + } + } + pub fn with_vertical_pages(self) -> Self { + Self { + swipe: self.swipe.with_vertical_pages(), + ..self + } } } @@ -125,63 +287,92 @@ where type Msg = FrameMsg; fn place(&mut self, bounds: Rect) -> Rect { - const TITLE_SPACE: i16 = theme::BUTTON_SPACING; - - let bounds = bounds.inset(self.border); - // Allowing for little longer titles to fit in - const TITLE_EXTRA_SPACE: Insets = Insets::right(2); - if let Some(b) = &mut self.button { - let button_side = theme::CORNER_BUTTON_SIDE; - let (header_area, button_area) = bounds.split_right(button_side); - let (button_area, _) = button_area.split_top(button_side); - b.place(button_area); - let title_area = self.title.place(header_area.outset(TITLE_EXTRA_SPACE)); - let remaining = header_area.inset(Insets::top(title_area.height())); - let subtitle_area = self.subtitle.place(remaining); - - let title_height = title_area.height() + subtitle_area.height(); - let header_height = title_height.max(button_side); - if title_height < button_side { - self.title - .place(title_area.translate(Offset::y((button_side - title_height) / 2))); - self.subtitle - .place(subtitle_area.translate(Offset::y((button_side - title_height) / 2))); - } - let content_area = bounds.inset(Insets::top(header_height + TITLE_SPACE)); - self.content.place(content_area); - } else { - let title_area = self.title.place(bounds.outset(TITLE_EXTRA_SPACE)); - let remaining = bounds.inset(Insets::top(title_area.height())); - let subtitle_area = self.subtitle.place(remaining); - let remaining = remaining.inset(Insets::top(subtitle_area.height())); - let content_area = remaining.inset(Insets::top(TITLE_SPACE)); - self.content.place(content_area); - } + self.bounds = bounds; + let content_area = frame_place(&mut self.header, &mut self.footer, bounds); + + self.content.place(content_area); + bounds } fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option { - self.title.event(ctx, event); - self.subtitle.event(ctx, event); - if let Some(ButtonMsg::Clicked) = self.button.event(ctx, event) { - return Some(FrameMsg::Button(self.button_msg)); + if let Some(value) = frame_event( + &mut self.horizontal_swipe, + self.swipe, + &mut self.header, + &mut self.footer, + ctx, + event, + ) { + return Some(FrameMsg::Button(value)); } - self.content.event(ctx, event).map(FrameMsg::Content) + + let msg = self.content.event(ctx, event).map(FrameMsg::Content); + if let Some(count) = ctx.page_count() { + self.internal_page_cnt = count; + } + + if msg.is_some() { + return msg; + } + + None } fn paint(&mut self) { - self.title.paint(); - self.subtitle.paint(); - self.button.paint(); + self.header.paint(); + self.footer.paint(); self.content.paint(); } + fn render<'s>(&'s self, target: &mut impl Renderer<'s>) { + self.header.render(target); + self.footer.render(target); + self.content.render(target); + + self.horizontal_swipe + .render_swipe_cover(target, self.bounds); + } +} +fn frame_event( + horizontal_swipe: &mut HorizontalSwipe, + swipe_config: SwipeConfig, + header: &mut Header, + footer: &mut Option