diff --git a/.github/workflows/test-mobile-e2e.yml b/.github/workflows/test-mobile-e2e.yml
index 159068c005af..0c443893898f 100644
--- a/.github/workflows/test-mobile-e2e.yml
+++ b/.github/workflows/test-mobile-e2e.yml
@@ -21,6 +21,19 @@ on:
base_ref:
description: The base branch to merge the head into when checking out the code
required: false
+ export_to_xray:
+ description: Send tests results to Xray
+ required: false
+ type: boolean
+ default: false
+ test_execution_android:
+ description: "[Android] Test Execution ticket ID. Ex: 'B2CQA-2461'"
+ required: false
+ type: string
+ test_execution_ios:
+ description: "[iOS] Test Execution ticket ID. Ex: 'B2CQA-2461'"
+ required: false
+ type: string
# Uncomment to have log-level: trace on detox run and build
# (cf: apps/ledger-live-mobile/detox.config.js)
@@ -287,6 +300,63 @@ jobs:
password: ${{ secrets.ALLURE_LEDGER_LIVE_PASSWORD }}
path: android-test-artifacts
+ upload-to-xray:
+ name: "Upload to Xray"
+ runs-on: [ledger-live-medium]
+ strategy:
+ matrix:
+ platform:
+ - android
+ - ios
+ fail-fast: false
+ env:
+ XRAY_CLIENT_ID: ${{ secrets.XRAY_CLIENT_ID }}
+ XRAY_CLIENT_SECRET: ${{ secrets.XRAY_CLIENT_SECRET }}
+ XRAY_API_URL: https://xray.cloud.getxray.app/api/v2
+ JIRA_URL: https://ledgerhq.atlassian.net/browse
+ TEST_EXECUTION: ${{ matrix.platform == 'android' && inputs.test_execution_android || inputs.test_execution_ios }}
+ needs: [detox-tests-android, detox-tests-ios]
+ if: ${{ !cancelled() && inputs.export_to_xray }}
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ inputs.ref || github.sha }}
+
+ - name: Download Allure Results
+ uses: actions/download-artifact@v4
+ with:
+ path: "artifacts-${{ matrix.platform }}"
+ name: ${{ matrix.platform }}-test-artifacts
+
+ - name: Format Xray results
+ run: apps/ledger-live-mobile/e2e/xray.formater.sh artifacts-${{ matrix.platform }} ${{ matrix.platform }} ${{ env.TEST_EXECUTION}}
+
+ - name: Upload aggregated xray results
+ uses: actions/upload-artifact@v4
+ with:
+ retention-days: 1
+ name: xray-reports-${{ matrix.platform }}
+ path: "artifacts-${{ matrix.platform }}/xray_report.json"
+
+ - name: Authenticate to Xray
+ id: authenticate
+ run: |
+ response=$(curl -H "Content-Type: application/json" -X POST --data '{"client_id": "${{ env.XRAY_CLIENT_ID }}", "client_secret": "${{ env.XRAY_CLIENT_SECRET }}"}' ${{ env.XRAY_API_URL }}/authenticate)
+ echo "xray_token=$response" >> $GITHUB_OUTPUT
+ - name: Publish report on Xray
+ id: publish-xray
+ run: |
+ response=$(curl -H "Content-Type: application/json" \
+ -H "Authorization: Bearer ${{ steps.authenticate.outputs.xray_token }}" \
+ -X POST \
+ --data @artifacts-${{ matrix.platform }}/xray_report.json \
+ ${{ env.XRAY_API_URL }}/import/execution)
+ key=$(echo $response | jq -r '.key')
+ echo "xray_key=$key" >> $GITHUB_OUTPUT
+ - name: Write Xray report link in summary
+ shell: bash
+ run: echo "::notice title=${{ matrix.platform }} Xray report URL::${{ env.JIRA_URL }}/${{ steps.publish-xray.outputs.xray_key }}"
+
report:
needs: [detox-tests-android, detox-tests-ios]
runs-on: ubuntu-latest
diff --git a/.github/workflows/test-ui-e2e-only-desktop.yml b/.github/workflows/test-ui-e2e-only-desktop.yml
index e61f725a82d7..35be80bd8d86 100644
--- a/.github/workflows/test-ui-e2e-only-desktop.yml
+++ b/.github/workflows/test-ui-e2e-only-desktop.yml
@@ -58,8 +58,6 @@ permissions:
jobs:
e2e-tests-linux:
name: "Desktop Tests E2E (Ubuntu)"
- outputs:
- status: ${{ steps.tests.outcome }}
env:
NODE_OPTIONS: "--max-old-space-size=7168"
INSTRUMENT_BUILD: true
@@ -78,7 +76,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.sha }}
-
+
- name: Setup broadcast environment variables
id: set-env
run: |
@@ -98,18 +96,21 @@ jobs:
roleName: ${{ secrets.AWS_CACHE_ROLE_NAME }}
region: ${{ secrets.AWS_CACHE_REGION }}
turbo-server-token: ${{ secrets.TURBOREPO_SERVER_TOKEN }}
+
- uses: LedgerHQ/ledger-live/tools/actions/composites/setup-test-desktop@develop
id: setup-test-desktop
with:
skip_ruby: true
install_playwright: true
turborepo-server-port: ${{ steps.caches.outputs.port }}
+
- name: Generate token
id: generate-token
uses: tibdex/github-app-token@v1
with:
app_id: ${{ secrets.GH_BOT_APP_ID }}
private_key: ${{ secrets.GH_BOT_PRIVATE_KEY }}
+
- name: Retrieving coin apps
uses: actions/checkout@v4
with:
@@ -117,9 +118,11 @@ jobs:
repository: LedgerHQ/coin-apps
token: ${{ steps.generate-token.outputs.token }}
path: coin-apps
+
- name: Pull docker image
run: docker pull ${{ env.SPECULOS_IMAGE_TAG }}
shell: bash
+
- name: Run playwright tests [Linux => xvfb-run]
id: tests
run: |
@@ -188,6 +191,7 @@ jobs:
- name: Get summary
if: ${{ !cancelled() }}
+ id: summary
shell: bash
run: |
cd apps/ledger-live-desktop
@@ -200,15 +204,12 @@ jobs:
totalTests=$(jq '.statistic.total' summary.json)
echo "TEST_RESULT=$passedTests passed, $failedTests failed, $brokenTests broken, $skippedTests skipped, $totalTests total" >> $GITHUB_ENV
- - name: Get status color
- if: ${{ !cancelled() }}
- shell: bash
- run: >
- if ${{ needs.e2e-tests-linux.outputs.status == 'success' }};
- then echo "STATUS_COLOR=#33FF39" >> $GITHUB_ENV;
- elif ${{ needs.e2e-tests-linux.outputs.status == 'failure' }};
- then echo "STATUS_COLOR=#FF333C" >> $GITHUB_ENV;
- else echo "STATUS_COLOR=#F3FF33" >> $GITHUB_ENV;
+ if [ "$failedTests" -gt 0 ] || [ "$brokenTests" -gt 0 ]; then
+ echo "STATUS_COLOR=#FF333C" >> $GITHUB_ENV;
+ echo "STATUS_EMOJI=❌" >> $GITHUB_ENV;
+ else
+ echo "STATUS_COLOR=#33FF39" >> $GITHUB_ENV;
+ echo "STATUS_EMOJI=✅" >> $GITHUB_ENV;
fi
- uses: actions/github-script@v6
@@ -246,6 +247,7 @@ jobs:
status: "${{ needs.e2e-tests-linux.outputs.status }}",
}
};
+ const statusEmoji = process.env.STATUS_EMOJI;
let summary = `### Playwright Tests
`
@@ -270,7 +272,7 @@ jobs:
|`;
Object.entries(report).forEach(([os, values]) => {
- summary += ` ${values.pass ? "✅" : "❌"} (${values.status}) |`;
+ summary += ` ${values.pass ? statusEmoji : "❌"} (${values.status}) |`;
});
summary += `
@@ -318,7 +320,7 @@ jobs:
"type": "section",
"text": {
"type": "mrkdwn",
- "text": `- 🐧 linux: ${report.linux.pass ? "✅" : "❌"} ${process.env.TEST_RESULT || 'No test results'}`
+ "text": `- 🐧 linux: ${statusEmoji} ${process.env.TEST_RESULT || 'No test results'}`
}
},
{
@@ -356,6 +358,7 @@ jobs:
payload-file-path: ${{ github.workspace }}/payload-slack-content.json
env:
SLACK_BOT_TOKEN: ${{ secrets.SLACK_LIVE_CI_BOT_TOKEN }}
+ STATUS_COLOR: ${{ env.STATUS_COLOR }}
upload-to-xray:
name: "Upload to Xray"
diff --git a/CODEOWNERS b/CODEOWNERS
index f8d1a5615788..fa6675e1f307 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -99,10 +99,12 @@ apps/ledger-live-mobile/src/newArch/features/Web3Hub/ @ledgerhq/wallet-api
# Devices team
apps/cli/src/commands/devices @ledgerhq/live-devices
**/src/renderer/screens/manager/ @ledgerhq/live-devices
-**/screens/CustomImage @ledgerhq/live-devices
-**/components/CustomImage @ledgerhq/live-devices
+**/screens/customImage @ledgerhq/live-devices
+**/components/CustomImage @ledgerhq/live-devices
+**/screens/CustomImage @ledgerhq/live-devices
**/SyncOnboarding/** @ledgerhq/live-devices
**/OnboardingAppInstall/** @ledgerhq/live-devices
+**/UpdateFirmwareModal/** @ledgerhq/live-devices
apps/**/components/DeviceAction/ @ledgerhq/live-devices
apps/ledger-live-mobile/src/screens/MyLedger*/ @ledgerhq/live-devices
apps/ledger-live-mobile/src/newArch/features/FirmwareUpdate/ @ledgerhq/live-devices
diff --git a/README.md b/README.md
index 3ee3d83d8b63..d1251e36024b 100644
--- a/README.md
+++ b/README.md
@@ -78,7 +78,7 @@ pnpm mobile pod
### Tools
-We use [**pnpm workspaces**](https://pnpm.io/) and [**turborepo**](https://turborepo.org/) under the hood to handle local and external dependencies, orchestrate tasks and perform various optimizations like package hoisting or [**remote caching**](https://turborepo.org/docs/features/remote-caching).
+We use [**pnpm workspaces**](https://pnpm.io/) and [**turborepo**](https://turborepo.org/) under the hood to handle local and external dependencies, orchestrate tasks and perform various optimizations like package hoisting or [**remote caching**](https://turbo.build/repo/docs/core-concepts/remote-caching).
For changelog generation releases and package publishing we rely on the [**changesets**](https://github.com/changesets/changesets) library.
diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md
index 7c2a5735c303..267107343c77 100644
--- a/apps/cli/CHANGELOG.md
+++ b/apps/cli/CHANGELOG.md
@@ -1,5 +1,51 @@
# @ledgerhq/live-cli
+## 24.5.2
+
+### Patch Changes
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/hw-transport-http@6.30.3
+ - @ledgerhq/hw-app-btc@10.4.2
+ - @ledgerhq/coin-bitcoin@0.8.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/live-countervalues@0.2.5
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/live-wallet@0.6.0
+ - @ledgerhq/hw-transport@6.31.3
+ - @ledgerhq/hw-transport-node-hid@6.29.4
+ - @ledgerhq/hw-transport-node-speculos@6.29.3
+ - @ledgerhq/hw-transport-mocker@6.29.3
+
+## 24.5.2-next.0
+
+### Patch Changes
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0-next.0
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/hw-transport-http@6.30.3-next.0
+ - @ledgerhq/hw-app-btc@10.4.2-next.0
+ - @ledgerhq/coin-bitcoin@0.8.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/live-countervalues@0.2.5-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/live-wallet@0.6.0-next.0
+ - @ledgerhq/hw-transport@6.31.3-next.0
+ - @ledgerhq/hw-transport-node-hid@6.29.4-next.0
+ - @ledgerhq/hw-transport-node-speculos@6.29.3-next.0
+ - @ledgerhq/hw-transport-mocker@6.29.3-next.0
+
## 24.5.1
### Patch Changes
diff --git a/apps/cli/package.json b/apps/cli/package.json
index ac6f3a964c5c..bfa274928b1d 100644
--- a/apps/cli/package.json
+++ b/apps/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/live-cli",
- "version": "24.5.1",
+ "version": "24.5.2",
"description": "ledger-live CLI version",
"repository": {
"type": "git",
diff --git a/apps/cli/src/commands/device/appUninstallAll.ts b/apps/cli/src/commands/device/appUninstallAll.ts
index 5d6ff93ddd00..fdc69300cf20 100644
--- a/apps/cli/src/commands/device/appUninstallAll.ts
+++ b/apps/cli/src/commands/device/appUninstallAll.ts
@@ -4,10 +4,8 @@ import { mergeMap, filter, map } from "rxjs/operators";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import getDeviceInfo from "@ledgerhq/live-common/hw/getDeviceInfo";
import { reducer, runAll } from "@ledgerhq/live-common/apps/index";
-import {
- listAppsUseCase,
- execWithTransport,
-} from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { listAppsUseCase } from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { execWithTransport } from "@ledgerhq/live-common/device/use-cases/execWithTransport";
import { command as uninstallAllApps } from "@ledgerhq/live-common/hw/uninstallAllApps";
import { deviceOpt } from "../../scan";
diff --git a/apps/cli/src/commands/device/appsCheckAllAppVersions.ts b/apps/cli/src/commands/device/appsCheckAllAppVersions.ts
index 792b7193b730..d9521e875558 100644
--- a/apps/cli/src/commands/device/appsCheckAllAppVersions.ts
+++ b/apps/cli/src/commands/device/appsCheckAllAppVersions.ts
@@ -10,10 +10,8 @@ import network from "@ledgerhq/live-network/network";
import installApp from "@ledgerhq/live-common/hw/installApp";
import uninstallApp from "@ledgerhq/live-common/hw/uninstallApp";
import { initState, reducer, runAll } from "@ledgerhq/live-common/apps/index";
-import {
- listAppsUseCase,
- execWithTransport,
-} from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { listAppsUseCase } from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { execWithTransport } from "@ledgerhq/live-common/device/use-cases/execWithTransport";
import { delay } from "@ledgerhq/live-common/promise";
import { getEnv } from "@ledgerhq/live-env";
import { getDependencies } from "@ledgerhq/live-common/apps/polyfill";
diff --git a/apps/cli/src/commands/device/appsInstallAll.ts b/apps/cli/src/commands/device/appsInstallAll.ts
index fadf3254c2e4..f079441116c1 100644
--- a/apps/cli/src/commands/device/appsInstallAll.ts
+++ b/apps/cli/src/commands/device/appsInstallAll.ts
@@ -4,10 +4,8 @@ import { mergeMap, filter, map } from "rxjs/operators";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import getDeviceInfo from "@ledgerhq/live-common/hw/getDeviceInfo";
import { initState, reducer, runAll } from "@ledgerhq/live-common/apps/index";
-import {
- listAppsUseCase,
- execWithTransport,
-} from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { listAppsUseCase } from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { execWithTransport } from "@ledgerhq/live-common/device/use-cases/execWithTransport";
import { deviceOpt } from "../../scan";
export default {
description: "test script to install and uninstall all apps",
diff --git a/apps/cli/src/commands/device/appsUpdateTestAll.ts b/apps/cli/src/commands/device/appsUpdateTestAll.ts
index 7df4b709f20a..9537f139d7c3 100644
--- a/apps/cli/src/commands/device/appsUpdateTestAll.ts
+++ b/apps/cli/src/commands/device/appsUpdateTestAll.ts
@@ -4,10 +4,8 @@ import { mergeMap, ignoreElements, filter, map } from "rxjs/operators";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import getDeviceInfo from "@ledgerhq/live-common/hw/getDeviceInfo";
import { initState, reducer, runAll, getActionPlan } from "@ledgerhq/live-common/apps/index";
-import {
- listAppsUseCase,
- execWithTransport,
-} from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { listAppsUseCase } from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { execWithTransport } from "@ledgerhq/live-common/device/use-cases/execWithTransport";
import type { AppOp } from "@ledgerhq/live-common/apps/types";
import { deviceOpt } from "../../scan";
diff --git a/apps/cli/src/commands/device/devDeviceAppsScenario.ts b/apps/cli/src/commands/device/devDeviceAppsScenario.ts
index b43d4471b439..9678605c3765 100644
--- a/apps/cli/src/commands/device/devDeviceAppsScenario.ts
+++ b/apps/cli/src/commands/device/devDeviceAppsScenario.ts
@@ -4,10 +4,8 @@ import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import getDeviceInfo from "@ledgerhq/live-common/hw/getDeviceInfo";
import { initState, ListAppsResult, reducer, runAll } from "@ledgerhq/live-common/apps/index";
import ManagerAPI from "@ledgerhq/live-common/manager/api";
-import {
- listAppsUseCase,
- execWithTransport,
-} from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { listAppsUseCase } from "@ledgerhq/live-common/device/use-cases/listAppsUseCase";
+import { execWithTransport } from "@ledgerhq/live-common/device/use-cases/execWithTransport";
import installApp from "@ledgerhq/live-common/hw/installApp";
import { deviceOpt } from "../../scan";
import { Application } from "@ledgerhq/types-live";
diff --git a/apps/cli/src/live-common-setup-base.ts b/apps/cli/src/live-common-setup-base.ts
index ff2370140a86..b143093b8cbc 100644
--- a/apps/cli/src/live-common-setup-base.ts
+++ b/apps/cli/src/live-common-setup-base.ts
@@ -34,7 +34,6 @@ setSupportedCurrencies([
"qtum",
"bitcoin_gold",
"komodo",
- "pivx",
"zencash",
"bitcoin_testnet",
"ethereum_sepolia",
diff --git a/apps/ledger-live-desktop/.prettierignore b/apps/ledger-live-desktop/.prettierignore
index 83e5bc2c893d..89f808a1c31a 100644
--- a/apps/ledger-live-desktop/.prettierignore
+++ b/apps/ledger-live-desktop/.prettierignore
@@ -3,4 +3,6 @@ src/renderer/families/generated.ts
analytics.min.js
src/renderer/animations/**/*.json
src/renderer/components/Onboarding/Screens/Tutorial/assets/animations/**/*.json
-tests/artifacts
\ No newline at end of file
+tests/artifacts
+tests/**/*-snapshots/
+
diff --git a/apps/ledger-live-desktop/.unimportedrc.json b/apps/ledger-live-desktop/.unimportedrc.json
index 975e764b562a..4ea42c55028b 100644
--- a/apps/ledger-live-desktop/.unimportedrc.json
+++ b/apps/ledger-live-desktop/.unimportedrc.json
@@ -21,10 +21,7 @@
"src/generate-cryptoassets-md.ts",
"src/newArch/features/Collectibles/**",
- "src/newArch/features/AnalyticsOptInPrompt/**",
- "src/newArch/features/WalletSync/**",
- "src/newArch/components/ContextMenu/**",
- "src/newArch/components/BreadCrumb/**",
+ "src/newArch/features/WalletSync/__tests__/shared.tsx",
"src/renderer/DesktopStorageProvider.ts"
],
"ignoreUnused": [
@@ -32,7 +29,9 @@
"@types/qrcode",
"@types/react-key-handler",
"prop-types",
- "allure-commandline"
+ "allure-commandline",
+ "msw",
+ "undici"
],
"aliases": {
"~/*": ["./src/*"]
diff --git a/apps/ledger-live-desktop/CHANGELOG.md b/apps/ledger-live-desktop/CHANGELOG.md
index 5931e85b5c0b..06cdeb79679f 100644
--- a/apps/ledger-live-desktop/CHANGELOG.md
+++ b/apps/ledger-live-desktop/CHANGELOG.md
@@ -1,5 +1,379 @@
# ledger-live-desktop
+## 2.86.0
+
+### Minor Changes
+
+- [#7634](https://github.com/LedgerHQ/ledger-live/pull/7634) [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198) Thanks [@Justkant](https://github.com/Justkant)! - feat: add dependencies support on wallet-api and dapp browser for transaction
+
+- [#7646](https://github.com/LedgerHQ/ledger-live/pull/7646) [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added the synchronization of a trustchain from mobile to desktop by scanning the QR code
+
+- [#7414](https://github.com/LedgerHQ/ledger-live/pull/7414) [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add ERC20 token support for filecoin
+
+- [#7737](https://github.com/LedgerHQ/ledger-live/pull/7737) [`5f88c36`](https://github.com/LedgerHQ/ledger-live/commit/5f88c36e77fb9064fd70bcb59c1763998dfbfc0f) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Fix Desktop Analytics
+
+- [#7633](https://github.com/LedgerHQ/ledger-live/pull/7633) [`e5419de`](https://github.com/LedgerHQ/ledger-live/commit/e5419ded434a3f6a203c0195932b5b846fec0e2c) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Rework QRCode Step in LLD + Add TabSelector in react-ui
+
+- [#7714](https://github.com/LedgerHQ/ledger-live/pull/7714) [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Improve account names module to avoid erasing custom names with the default ones when two instances are pushing around the same time
+
+- [#7691](https://github.com/LedgerHQ/ledger-live/pull/7691) [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added a Loading screen on LLM and LLD when initializing ledger sync while accounts are synchronizing
+
+- [#7776](https://github.com/LedgerHQ/ledger-live/pull/7776) [`3eafc83`](https://github.com/LedgerHQ/ledger-live/commit/3eafc83ced804fa63e1521e7defb3a0ce3e45a2f) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: remove error from btc fee drawer
+
+- [#7696](https://github.com/LedgerHQ/ledger-live/pull/7696) [`dd4daf1`](https://github.com/LedgerHQ/ledger-live/commit/dd4daf1a1b5e38d46c2985bf99838c587bbc7ced) Thanks [@chrisduma-ledger](https://github.com/chrisduma-ledger)! - Adds confirmation message for Sell in LLD
+
+- [#7440](https://github.com/LedgerHQ/ledger-live/pull/7440) [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194) Thanks [@thesan](https://github.com/thesan)! - Request device access within `HWDeviceProvider`
+
+- [#7767](https://github.com/LedgerHQ/ledger-live/pull/7767) [`dbc0a9a`](https://github.com/LedgerHQ/ledger-live/commit/dbc0a9ab83f30c225950bdd5189216f7d4735c8e) Thanks [@CremaFR](https://github.com/CremaFR)! - fix fee drawer issues by prepararing tx
+
+- [#7572](https://github.com/LedgerHQ/ledger-live/pull/7572) [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6) Thanks [@valpinkman](https://github.com/valpinkman)! - Implement new app data backup and restore when installing, uninstalling or updating app on the device
+
+- [#7742](https://github.com/LedgerHQ/ledger-live/pull/7742) [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: some issue with btc custom fees when reopening drawer
+
+- [#7706](https://github.com/LedgerHQ/ledger-live/pull/7706) [`84ea362`](https://github.com/LedgerHQ/ledger-live/commit/84ea362e10ef5885428248c5689ae9ae595e653f) Thanks [@thesan](https://github.com/thesan)! - Create the `/ledgersync` deeplink
+
+### Patch Changes
+
+- [#7541](https://github.com/LedgerHQ/ledger-live/pull/7541) [`7f588f3`](https://github.com/LedgerHQ/ledger-live/commit/7f588f36ff95a6c05fac4c971bf432fcc0101fcc) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add Error screen when PinCode doesn't match
+
+- [#7763](https://github.com/LedgerHQ/ledger-live/pull/7763) [`0450315`](https://github.com/LedgerHQ/ledger-live/commit/045031517599cd4dd9e2809ab6bc7c57ca9fdf46) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - use account id instead of currency id for sla passthrough
+
+- [#7602](https://github.com/LedgerHQ/ledger-live/pull/7602) [`e8db656`](https://github.com/LedgerHQ/ledger-live/commit/e8db656c625d0bf6a00ab340af6e3b9d4d79498d) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - Add demo3 manifest ids
+
+- [#7565](https://github.com/LedgerHQ/ledger-live/pull/7565) [`6449fc7`](https://github.com/LedgerHQ/ledger-live/commit/6449fc7651cb327b3acf29f43fe13a170acde604) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Add discover section deep link initial category filter to enable links like ledgerlive://discover?category=restaking to load the discover section with an initial category pre-selected.
+
+- [#7539](https://github.com/LedgerHQ/ledger-live/pull/7539) [`9581686`](https://github.com/LedgerHQ/ledger-live/commit/958168623e2c61cdd8b214e98dd132b59d966751) Thanks [@cksanders](https://github.com/cksanders)! - Fix Recover support to include LSP for Restore
+
+- [#7641](https://github.com/LedgerHQ/ledger-live/pull/7641) [`3b944af`](https://github.com/LedgerHQ/ledger-live/commit/3b944af87a841475b2946942b5e29b571e6ccc63) Thanks [@CremaFR](https://github.com/CremaFR)! - fix btc fee drawer for swaap
+
+- [#7745](https://github.com/LedgerHQ/ledger-live/pull/7745) [`917045c`](https://github.com/LedgerHQ/ledger-live/commit/917045c9985386d3a5ad879ae9fec0f32322ddaa) Thanks [@LucasWerey](https://github.com/LucasWerey)! - LLD ORDINALS add dummy table to display inscriptions inside BTC account screen.
+
+- [#7677](https://github.com/LedgerHQ/ledger-live/pull/7677) [`3de9eb6`](https://github.com/LedgerHQ/ledger-live/commit/3de9eb6725cd32a5c90c6fedb9cb1dfffb6e4306) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Revamp LedgerSyncDebugger
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7682](https://github.com/LedgerHQ/ledger-live/pull/7682) [`9f39f91`](https://github.com/LedgerHQ/ledger-live/commit/9f39f9129668c22dc23f15be9304224ac17dce1d) Thanks [@CremaFR](https://github.com/CremaFR)! - fixed swap live app fee drawer error check sync
+
+- [#7664](https://github.com/LedgerHQ/ledger-live/pull/7664) [`f00f598`](https://github.com/LedgerHQ/ledger-live/commit/f00f598e32e7868e41fbd5d5d5822cc897959ff5) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Remove Export account when LedgerSync FF is On
+
+- [#7793](https://github.com/LedgerHQ/ledger-live/pull/7793) [`c76dfe4`](https://github.com/LedgerHQ/ledger-live/commit/c76dfe4102c5dbf9fb2c5a23ff8555d2741a053d) Thanks [@chrisduma-ledger](https://github.com/chrisduma-ledger)! - Fixes View Details button for the Swap Live App
+
+- [#7561](https://github.com/LedgerHQ/ledger-live/pull/7561) [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix get Members errors GetMember :Error: ["useGetMembers", null] data is undefined
+
+- [#7297](https://github.com/LedgerHQ/ledger-live/pull/7297) [`c01f17e`](https://github.com/LedgerHQ/ledger-live/commit/c01f17eaf57ef01021aecd5415cb64cedfe317a9) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add msw for integration tests. Add entry points for nft gallery newarch under ff. Mock some modules from polkadot that are not compatible with msw
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7725](https://github.com/LedgerHQ/ledger-live/pull/7725) [`b2c4c51`](https://github.com/LedgerHQ/ledger-live/commit/b2c4c514afe35422c75f5de26c9ae45c67c10b01) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update errors in trad
+
+- [#7672](https://github.com/LedgerHQ/ledger-live/pull/7672) [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add support for jettons
+
+- [#7694](https://github.com/LedgerHQ/ledger-live/pull/7694) [`6f865fd`](https://github.com/LedgerHQ/ledger-live/commit/6f865fd52119a017ea20fd8f51b6e30ebf00fe68) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: uses correct status for fee drawers and disable button if any error is present
+
+- [#7297](https://github.com/LedgerHQ/ledger-live/pull/7297) [`c01f17e`](https://github.com/LedgerHQ/ledger-live/commit/c01f17eaf57ef01021aecd5415cb64cedfe317a9) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Rework of the nfts gallery under newArch to prepare Ordinals integration and setup for msw
+
+- [#7757](https://github.com/LedgerHQ/ledger-live/pull/7757) [`b606b71`](https://github.com/LedgerHQ/ledger-live/commit/b606b7143873c037c0507a479e2789917db82b48) Thanks [@liviuciulinaru](https://github.com/liviuciulinaru)! - error messages for transaction and fees drawers
+
+- [#7525](https://github.com/LedgerHQ/ledger-live/pull/7525) [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576) Thanks [@valpinkman](https://github.com/valpinkman)! - Add new developer setting to mock app update in the manager
+
+- [#7756](https://github.com/LedgerHQ/ledger-live/pull/7756) [`1503fd7`](https://github.com/LedgerHQ/ledger-live/commit/1503fd772a040e1208802ab0d4e4469aba6e5005) Thanks [@LucasWerey](https://github.com/LucasWerey)! - add the ui of rare sats table for ordinals
+
+- [#7712](https://github.com/LedgerHQ/ledger-live/pull/7712) [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Handle TrustchainAlreadyInitialized & TrustchainAlreadyInitializedWithOtherSeed on Scan QR
+
+- [#7678](https://github.com/LedgerHQ/ledger-live/pull/7678) [`b91295b`](https://github.com/LedgerHQ/ledger-live/commit/b91295b40dcdd8ab4768c49505e60bf51ebfae11) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Improve logs export: merge logs from all process in chronological order and ordered keys in JSON. Fix compatibility of internal process logs with LogsViewer tool (timestamp was broken, pname was not used).
+
+- [#7569](https://github.com/LedgerHQ/ledger-live/pull/7569) [`fc6a11a`](https://github.com/LedgerHQ/ledger-live/commit/fc6a11ab619ca6c4ec9e69b5239f99ec28c9e734) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix existing custom lock screen not being recognized in My Ledger ("Add" displayed instead of "Change" and no option to delete the current lock screen picture)
+
+- [#7577](https://github.com/LedgerHQ/ledger-live/pull/7577) [`9badf39`](https://github.com/LedgerHQ/ledger-live/commit/9badf390838517c751b61159ad2b0c8a0285d0ea) Thanks [@LucasWerey](https://github.com/LucasWerey)! - WS change wording
+
+- [#7632](https://github.com/LedgerHQ/ledger-live/pull/7632) [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - LLM / LLD - Fix the getOrCreateTrustchain that wasn't working when another instance destroyed the trustchain
+
+- [#7627](https://github.com/LedgerHQ/ledger-live/pull/7627) [`a442d80`](https://github.com/LedgerHQ/ledger-live/commit/a442d808bcc48a820623260b1501321ede85cb76) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add CTAs on missing screens for LedgerSync
+
+- [#7766](https://github.com/LedgerHQ/ledger-live/pull/7766) [`77f9a5e`](https://github.com/LedgerHQ/ledger-live/commit/77f9a5e1b15d7ab0d3ff87ce328cbff84ae9c386) Thanks [@lpaquet-ledger](https://github.com/lpaquet-ledger)! - add forgetten param demo 3 to live app
+
+- [#7542](https://github.com/LedgerHQ/ledger-live/pull/7542) [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - My Ledger: fix & refactor logic of "is app supported by Ledger Live" depending on feature flags, and associated filters in apps catalog. Now this logic is in one single place and fully unit tested.
+
+- [#7685](https://github.com/LedgerHQ/ledger-live/pull/7685) [`238efb7`](https://github.com/LedgerHQ/ledger-live/commit/238efb7bb2a13f0e494338a9c9247d66c841577f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update Copy on manageKey Flow
+
+- [#7687](https://github.com/LedgerHQ/ledger-live/pull/7687) [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Handling alredy created key with new or same Ledger device
+
+- [#7656](https://github.com/LedgerHQ/ledger-live/pull/7656) [`6460687`](https://github.com/LedgerHQ/ledger-live/commit/646068770181c5cfd112ab050ca26d871cfce835) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: btc fee drawer can be close on swap live app
+
+- [#7744](https://github.com/LedgerHQ/ledger-live/pull/7744) [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86) Thanks [@valpinkman](https://github.com/valpinkman)! - Delete local app data when uninstalling apps
+
+- [#7556](https://github.com/LedgerHQ/ledger-live/pull/7556) [`ebbbe52`](https://github.com/LedgerHQ/ledger-live/commit/ebbbe521b62c91be646925ff6c87fd79357cff82) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Throw errors to avoid rejection on QRCode
+
+- [#7717](https://github.com/LedgerHQ/ledger-live/pull/7717) [`9a4a3bc`](https://github.com/LedgerHQ/ledger-live/commit/9a4a3bce55a2332ae4bdb13cc2bdbbb97ed7693b) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix minor bugs on both LL
+
+- [#7702](https://github.com/LedgerHQ/ledger-live/pull/7702) [`7430d8e`](https://github.com/LedgerHQ/ledger-live/commit/7430d8e2bb97be33dd2a21c31de8b9984f28a702) Thanks [@Justkant](https://github.com/Justkant)! - perf: improve perf by using the networks instead of listing currencies to match
+
+- [#7752](https://github.com/LedgerHQ/ledger-live/pull/7752) [`c68c312`](https://github.com/LedgerHQ/ledger-live/commit/c68c3121b93d38567f31682c9a4b191f29db02a0) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - Pass through from currency if exists in location to demo 3
+
+- [#7573](https://github.com/LedgerHQ/ledger-live/pull/7573) [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752) Thanks [@liviuciulinaru](https://github.com/liviuciulinaru)! - [swap] setup demo3 flag and routes
+
+- [#7662](https://github.com/LedgerHQ/ledger-live/pull/7662) [`4485e37`](https://github.com/LedgerHQ/ledger-live/commit/4485e3792b6ad7517a923f220858e667dbc7c97a) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add more precise name for LLD Instances
+
+- [#7592](https://github.com/LedgerHQ/ledger-live/pull/7592) [`a354886`](https://github.com/LedgerHQ/ledger-live/commit/a354886e05e12b519f89d93cee079bbff3104723) Thanks [@Wozacosta](https://github.com/Wozacosta)! - fixes display of account unit during send
+
+- [#7734](https://github.com/LedgerHQ/ledger-live/pull/7734) [`255f035`](https://github.com/LedgerHQ/ledger-live/commit/255f035b8415eb09683f959e37593e1969f5911c) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add rare satoshis icons to ui package and a mapping inside LLD to use them
+
+- [#7715](https://github.com/LedgerHQ/ledger-live/pull/7715) [`f4bb881`](https://github.com/LedgerHQ/ledger-live/commit/f4bb881f79b38d2a1798933a4a5cd713167fad72) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: persistant gasOptions between evm chains creating crashes
+
+- [#7731](https://github.com/LedgerHQ/ledger-live/pull/7731) [`e1d6d7d`](https://github.com/LedgerHQ/ledger-live/commit/e1d6d7d72059db3db29c8968364c4d348398446b) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add vertical scroll inside optin prompt and correct variable name. Fix export account row from settings that was hidden when LS enabled
+
+- [#7585](https://github.com/LedgerHQ/ledger-live/pull/7585) [`aadad07`](https://github.com/LedgerHQ/ledger-live/commit/aadad0732479f99bf502378fd74805f5a6f842f4) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: render loader on result for startExchange
+
+- [#7663](https://github.com/LedgerHQ/ledger-live/pull/7663) [`1a5bcec`](https://github.com/LedgerHQ/ledger-live/commit/1a5bcecb79d6c29b895f5d2d317a7aec00013acf) Thanks [@valpinkman](https://github.com/valpinkman)! - Avoid running watchloop when LS ff is disabled
+
+- [#7709](https://github.com/LedgerHQ/ledger-live/pull/7709) [`1f74063`](https://github.com/LedgerHQ/ledger-live/commit/1f7406327583cb61944cab18023e966b5ac467aa) Thanks [@CremaFR](https://github.com/CremaFR)! - btc and evm fee drawer display amount errors when editing fees too high
+
+- [#7711](https://github.com/LedgerHQ/ledger-live/pull/7711) [`e5c578b`](https://github.com/LedgerHQ/ledger-live/commit/e5c578b7be3fe0653bc7fced49eb5713b134f741) Thanks [@CremaFR](https://github.com/CremaFR)! - fix setTransaction fee drawer call to check error status
+
+- [#7660](https://github.com/LedgerHQ/ledger-live/pull/7660) [`9c584a0`](https://github.com/LedgerHQ/ledger-live/commit/9c584a08063dedc4eb4baeb3b0e719acf98a2087) Thanks [@sergiubreban](https://github.com/sergiubreban)! - removes old manifest id for buy-sell app
+
+- [#7527](https://github.com/LedgerHQ/ledger-live/pull/7527) [`c7b5135`](https://github.com/LedgerHQ/ledger-live/commit/c7b5135a2a81311fba8a706790ae3c7dadd4a32a) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix firmware update for old firmware versions
+
+- [#7657](https://github.com/LedgerHQ/ledger-live/pull/7657) [`2359a8e`](https://github.com/LedgerHQ/ledger-live/commit/2359a8e34fbe1a1ac073b6d18d66d2942a5dd817) Thanks [@valpinkman](https://github.com/valpinkman)! - Prevent the use of webp for Custom Lock Screen
+
+- [#7680](https://github.com/LedgerHQ/ledger-live/pull/7680) [`714a096`](https://github.com/LedgerHQ/ledger-live/commit/714a096a9310c0f502381f8ec0869c6a662b6ec9) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: uses native segwit empty address to compute btc fees
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- [#7555](https://github.com/LedgerHQ/ledger-live/pull/7555) [`aa9110f`](https://github.com/LedgerHQ/ledger-live/commit/aa9110feeb862d4c340e698950d0133d0eb1efb1) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Custom lock screen: disallow selection of gifs
+
+- [#7610](https://github.com/LedgerHQ/ledger-live/pull/7610) [`08fd8b4`](https://github.com/LedgerHQ/ledger-live/commit/08fd8b4c2150a32a72f2b943d1ef76724a1e2544) Thanks [@mwiercinska](https://github.com/mwiercinska)! - Add locale and ticker query params for buy/sell
+
+- [#7736](https://github.com/LedgerHQ/ledger-live/pull/7736) [`644332f`](https://github.com/LedgerHQ/ledger-live/commit/644332f58790fb89375b9ca8a4b58e5f1613c14f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix Animation Color
+
+- [#7629](https://github.com/LedgerHQ/ledger-live/pull/7629) [`81468af`](https://github.com/LedgerHQ/ledger-live/commit/81468af073af1ccdeb3fdbcf6b2c998cebc68ab5) Thanks [@mwiercinska](https://github.com/mwiercinska)! - add translation for back to quote CTA in WebPTXPlayer
+
+- [#7700](https://github.com/LedgerHQ/ledger-live/pull/7700) [`55f40b1`](https://github.com/LedgerHQ/ledger-live/commit/55f40b1c9bbc91ba7b4aada849c94987546bad75) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update analytics
+
+- [#7690](https://github.com/LedgerHQ/ledger-live/pull/7690) [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57) Thanks [@thesan](https://github.com/thesan)! - Refresh ledger sync QR code on expiration
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- [#7654](https://github.com/LedgerHQ/ledger-live/pull/7654) [`351cef9`](https://github.com/LedgerHQ/ledger-live/commit/351cef9caa68c1f88d1d709206ad5c3d5f22998b) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Minor copy update for LedgerSync
+
+- [#7679](https://github.com/LedgerHQ/ledger-live/pull/7679) [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix removal of custom lock screen on LLD
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`87c160d`](https://github.com/LedgerHQ/ledger-live/commit/87c160d855b512d5a0394eaee7626e2b8cd431ee), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`d60a022`](https://github.com/LedgerHQ/ledger-live/commit/d60a02238db9ed16142de4c1874e26d27aaaa98c), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`ef99222`](https://github.com/LedgerHQ/ledger-live/commit/ef99222a5adcd9732d06600bc875309c440e084f), [`e5419de`](https://github.com/LedgerHQ/ledger-live/commit/e5419ded434a3f6a203c0195932b5b846fec0e2c), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`8e0ac04`](https://github.com/LedgerHQ/ledger-live/commit/8e0ac04ac8cdaaee59633ebdf219e5dcf44a10df), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8ac662`](https://github.com/LedgerHQ/ledger-live/commit/c8ac662e6f88349187f802741e14c3d5fb67cddb), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`d213d81`](https://github.com/LedgerHQ/ledger-live/commit/d213d8122647d559b7a0f44e2beffa5e39c3249b), [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1), [`e7db725`](https://github.com/LedgerHQ/ledger-live/commit/e7db72552042ff4dd85bec236f6bd083fa3da533), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0
+ - @ledgerhq/trustchain@0.3.0
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/hw-transport-node-speculos-http@6.29.3
+ - @ledgerhq/hw-transport-http@6.30.3
+ - @ledgerhq/coin-bitcoin@0.8.0
+ - @ledgerhq/coin-evm@2.2.0
+ - @ledgerhq/domain-service@1.2.4
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/live-countervalues@0.2.5
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-countervalues-react@0.2.5
+ - @ledgerhq/react-ui@0.16.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/live-wallet@0.6.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/hw-trustchain@0.1.5
+ - @ledgerhq/coin-cosmos@0.1.1
+ - @ledgerhq/devices@8.4.3
+ - @ledgerhq/hw-transport@6.31.3
+ - @ledgerhq/hw-transport-node-hid-singleton@6.31.4
+ - @ledgerhq/hw-transport-vault@1.3.3
+ - @ledgerhq/live-nft@0.4.5
+ - @ledgerhq/live-nft-react@0.4.5
+
+## 2.86.0-next.1
+
+### Patch Changes
+
+- [#7793](https://github.com/LedgerHQ/ledger-live/pull/7793) [`c76dfe4`](https://github.com/LedgerHQ/ledger-live/commit/c76dfe4102c5dbf9fb2c5a23ff8555d2741a053d) Thanks [@chrisduma-ledger](https://github.com/chrisduma-ledger)! - Fixes View Details button for the Swap Live App
+
+## 2.86.0-next.0
+
+### Minor Changes
+
+- [#7634](https://github.com/LedgerHQ/ledger-live/pull/7634) [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198) Thanks [@Justkant](https://github.com/Justkant)! - feat: add dependencies support on wallet-api and dapp browser for transaction
+
+- [#7646](https://github.com/LedgerHQ/ledger-live/pull/7646) [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added the synchronization of a trustchain from mobile to desktop by scanning the QR code
+
+- [#7414](https://github.com/LedgerHQ/ledger-live/pull/7414) [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add ERC20 token support for filecoin
+
+- [#7737](https://github.com/LedgerHQ/ledger-live/pull/7737) [`5f88c36`](https://github.com/LedgerHQ/ledger-live/commit/5f88c36e77fb9064fd70bcb59c1763998dfbfc0f) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Fix Desktop Analytics
+
+- [#7633](https://github.com/LedgerHQ/ledger-live/pull/7633) [`e5419de`](https://github.com/LedgerHQ/ledger-live/commit/e5419ded434a3f6a203c0195932b5b846fec0e2c) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Rework QRCode Step in LLD + Add TabSelector in react-ui
+
+- [#7714](https://github.com/LedgerHQ/ledger-live/pull/7714) [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Improve account names module to avoid erasing custom names with the default ones when two instances are pushing around the same time
+
+- [#7691](https://github.com/LedgerHQ/ledger-live/pull/7691) [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added a Loading screen on LLM and LLD when initializing ledger sync while accounts are synchronizing
+
+- [#7776](https://github.com/LedgerHQ/ledger-live/pull/7776) [`3eafc83`](https://github.com/LedgerHQ/ledger-live/commit/3eafc83ced804fa63e1521e7defb3a0ce3e45a2f) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: remove error from btc fee drawer
+
+- [#7696](https://github.com/LedgerHQ/ledger-live/pull/7696) [`dd4daf1`](https://github.com/LedgerHQ/ledger-live/commit/dd4daf1a1b5e38d46c2985bf99838c587bbc7ced) Thanks [@chrisduma-ledger](https://github.com/chrisduma-ledger)! - Adds confirmation message for Sell in LLD
+
+- [#7440](https://github.com/LedgerHQ/ledger-live/pull/7440) [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194) Thanks [@thesan](https://github.com/thesan)! - Request device access within `HWDeviceProvider`
+
+- [#7767](https://github.com/LedgerHQ/ledger-live/pull/7767) [`dbc0a9a`](https://github.com/LedgerHQ/ledger-live/commit/dbc0a9ab83f30c225950bdd5189216f7d4735c8e) Thanks [@CremaFR](https://github.com/CremaFR)! - fix fee drawer issues by prepararing tx
+
+- [#7572](https://github.com/LedgerHQ/ledger-live/pull/7572) [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6) Thanks [@valpinkman](https://github.com/valpinkman)! - Implement new app data backup and restore when installing, uninstalling or updating app on the device
+
+- [#7742](https://github.com/LedgerHQ/ledger-live/pull/7742) [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: some issue with btc custom fees when reopening drawer
+
+- [#7706](https://github.com/LedgerHQ/ledger-live/pull/7706) [`84ea362`](https://github.com/LedgerHQ/ledger-live/commit/84ea362e10ef5885428248c5689ae9ae595e653f) Thanks [@thesan](https://github.com/thesan)! - Create the `/ledgersync` deeplink
+
+### Patch Changes
+
+- [#7541](https://github.com/LedgerHQ/ledger-live/pull/7541) [`7f588f3`](https://github.com/LedgerHQ/ledger-live/commit/7f588f36ff95a6c05fac4c971bf432fcc0101fcc) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add Error screen when PinCode doesn't match
+
+- [#7763](https://github.com/LedgerHQ/ledger-live/pull/7763) [`0450315`](https://github.com/LedgerHQ/ledger-live/commit/045031517599cd4dd9e2809ab6bc7c57ca9fdf46) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - use account id instead of currency id for sla passthrough
+
+- [#7602](https://github.com/LedgerHQ/ledger-live/pull/7602) [`e8db656`](https://github.com/LedgerHQ/ledger-live/commit/e8db656c625d0bf6a00ab340af6e3b9d4d79498d) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - Add demo3 manifest ids
+
+- [#7565](https://github.com/LedgerHQ/ledger-live/pull/7565) [`6449fc7`](https://github.com/LedgerHQ/ledger-live/commit/6449fc7651cb327b3acf29f43fe13a170acde604) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Add discover section deep link initial category filter to enable links like ledgerlive://discover?category=restaking to load the discover section with an initial category pre-selected.
+
+- [#7539](https://github.com/LedgerHQ/ledger-live/pull/7539) [`9581686`](https://github.com/LedgerHQ/ledger-live/commit/958168623e2c61cdd8b214e98dd132b59d966751) Thanks [@cksanders](https://github.com/cksanders)! - Fix Recover support to include LSP for Restore
+
+- [#7641](https://github.com/LedgerHQ/ledger-live/pull/7641) [`3b944af`](https://github.com/LedgerHQ/ledger-live/commit/3b944af87a841475b2946942b5e29b571e6ccc63) Thanks [@CremaFR](https://github.com/CremaFR)! - fix btc fee drawer for swaap
+
+- [#7745](https://github.com/LedgerHQ/ledger-live/pull/7745) [`917045c`](https://github.com/LedgerHQ/ledger-live/commit/917045c9985386d3a5ad879ae9fec0f32322ddaa) Thanks [@LucasWerey](https://github.com/LucasWerey)! - LLD ORDINALS add dummy table to display inscriptions inside BTC account screen.
+
+- [#7677](https://github.com/LedgerHQ/ledger-live/pull/7677) [`3de9eb6`](https://github.com/LedgerHQ/ledger-live/commit/3de9eb6725cd32a5c90c6fedb9cb1dfffb6e4306) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Revamp LedgerSyncDebugger
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7682](https://github.com/LedgerHQ/ledger-live/pull/7682) [`9f39f91`](https://github.com/LedgerHQ/ledger-live/commit/9f39f9129668c22dc23f15be9304224ac17dce1d) Thanks [@CremaFR](https://github.com/CremaFR)! - fixed swap live app fee drawer error check sync
+
+- [#7664](https://github.com/LedgerHQ/ledger-live/pull/7664) [`f00f598`](https://github.com/LedgerHQ/ledger-live/commit/f00f598e32e7868e41fbd5d5d5822cc897959ff5) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Remove Export account when LedgerSync FF is On
+
+- [#7561](https://github.com/LedgerHQ/ledger-live/pull/7561) [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix get Members errors GetMember :Error: ["useGetMembers", null] data is undefined
+
+- [#7297](https://github.com/LedgerHQ/ledger-live/pull/7297) [`c01f17e`](https://github.com/LedgerHQ/ledger-live/commit/c01f17eaf57ef01021aecd5415cb64cedfe317a9) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add msw for integration tests. Add entry points for nft gallery newarch under ff. Mock some modules from polkadot that are not compatible with msw
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7725](https://github.com/LedgerHQ/ledger-live/pull/7725) [`b2c4c51`](https://github.com/LedgerHQ/ledger-live/commit/b2c4c514afe35422c75f5de26c9ae45c67c10b01) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update errors in trad
+
+- [#7672](https://github.com/LedgerHQ/ledger-live/pull/7672) [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add support for jettons
+
+- [#7694](https://github.com/LedgerHQ/ledger-live/pull/7694) [`6f865fd`](https://github.com/LedgerHQ/ledger-live/commit/6f865fd52119a017ea20fd8f51b6e30ebf00fe68) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: uses correct status for fee drawers and disable button if any error is present
+
+- [#7297](https://github.com/LedgerHQ/ledger-live/pull/7297) [`c01f17e`](https://github.com/LedgerHQ/ledger-live/commit/c01f17eaf57ef01021aecd5415cb64cedfe317a9) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Rework of the nfts gallery under newArch to prepare Ordinals integration and setup for msw
+
+- [#7757](https://github.com/LedgerHQ/ledger-live/pull/7757) [`b606b71`](https://github.com/LedgerHQ/ledger-live/commit/b606b7143873c037c0507a479e2789917db82b48) Thanks [@liviuciulinaru](https://github.com/liviuciulinaru)! - error messages for transaction and fees drawers
+
+- [#7525](https://github.com/LedgerHQ/ledger-live/pull/7525) [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576) Thanks [@valpinkman](https://github.com/valpinkman)! - Add new developer setting to mock app update in the manager
+
+- [#7756](https://github.com/LedgerHQ/ledger-live/pull/7756) [`1503fd7`](https://github.com/LedgerHQ/ledger-live/commit/1503fd772a040e1208802ab0d4e4469aba6e5005) Thanks [@LucasWerey](https://github.com/LucasWerey)! - add the ui of rare sats table for ordinals
+
+- [#7712](https://github.com/LedgerHQ/ledger-live/pull/7712) [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Handle TrustchainAlreadyInitialized & TrustchainAlreadyInitializedWithOtherSeed on Scan QR
+
+- [#7678](https://github.com/LedgerHQ/ledger-live/pull/7678) [`b91295b`](https://github.com/LedgerHQ/ledger-live/commit/b91295b40dcdd8ab4768c49505e60bf51ebfae11) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Improve logs export: merge logs from all process in chronological order and ordered keys in JSON. Fix compatibility of internal process logs with LogsViewer tool (timestamp was broken, pname was not used).
+
+- [#7569](https://github.com/LedgerHQ/ledger-live/pull/7569) [`fc6a11a`](https://github.com/LedgerHQ/ledger-live/commit/fc6a11ab619ca6c4ec9e69b5239f99ec28c9e734) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix existing custom lock screen not being recognized in My Ledger ("Add" displayed instead of "Change" and no option to delete the current lock screen picture)
+
+- [#7577](https://github.com/LedgerHQ/ledger-live/pull/7577) [`9badf39`](https://github.com/LedgerHQ/ledger-live/commit/9badf390838517c751b61159ad2b0c8a0285d0ea) Thanks [@LucasWerey](https://github.com/LucasWerey)! - WS change wording
+
+- [#7632](https://github.com/LedgerHQ/ledger-live/pull/7632) [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - LLM / LLD - Fix the getOrCreateTrustchain that wasn't working when another instance destroyed the trustchain
+
+- [#7627](https://github.com/LedgerHQ/ledger-live/pull/7627) [`a442d80`](https://github.com/LedgerHQ/ledger-live/commit/a442d808bcc48a820623260b1501321ede85cb76) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add CTAs on missing screens for LedgerSync
+
+- [#7766](https://github.com/LedgerHQ/ledger-live/pull/7766) [`77f9a5e`](https://github.com/LedgerHQ/ledger-live/commit/77f9a5e1b15d7ab0d3ff87ce328cbff84ae9c386) Thanks [@lpaquet-ledger](https://github.com/lpaquet-ledger)! - add forgetten param demo 3 to live app
+
+- [#7542](https://github.com/LedgerHQ/ledger-live/pull/7542) [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - My Ledger: fix & refactor logic of "is app supported by Ledger Live" depending on feature flags, and associated filters in apps catalog. Now this logic is in one single place and fully unit tested.
+
+- [#7685](https://github.com/LedgerHQ/ledger-live/pull/7685) [`238efb7`](https://github.com/LedgerHQ/ledger-live/commit/238efb7bb2a13f0e494338a9c9247d66c841577f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update Copy on manageKey Flow
+
+- [#7687](https://github.com/LedgerHQ/ledger-live/pull/7687) [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Handling alredy created key with new or same Ledger device
+
+- [#7656](https://github.com/LedgerHQ/ledger-live/pull/7656) [`6460687`](https://github.com/LedgerHQ/ledger-live/commit/646068770181c5cfd112ab050ca26d871cfce835) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: btc fee drawer can be close on swap live app
+
+- [#7744](https://github.com/LedgerHQ/ledger-live/pull/7744) [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86) Thanks [@valpinkman](https://github.com/valpinkman)! - Delete local app data when uninstalling apps
+
+- [#7556](https://github.com/LedgerHQ/ledger-live/pull/7556) [`ebbbe52`](https://github.com/LedgerHQ/ledger-live/commit/ebbbe521b62c91be646925ff6c87fd79357cff82) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Throw errors to avoid rejection on QRCode
+
+- [#7717](https://github.com/LedgerHQ/ledger-live/pull/7717) [`9a4a3bc`](https://github.com/LedgerHQ/ledger-live/commit/9a4a3bce55a2332ae4bdb13cc2bdbbb97ed7693b) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix minor bugs on both LL
+
+- [#7702](https://github.com/LedgerHQ/ledger-live/pull/7702) [`7430d8e`](https://github.com/LedgerHQ/ledger-live/commit/7430d8e2bb97be33dd2a21c31de8b9984f28a702) Thanks [@Justkant](https://github.com/Justkant)! - perf: improve perf by using the networks instead of listing currencies to match
+
+- [#7752](https://github.com/LedgerHQ/ledger-live/pull/7752) [`c68c312`](https://github.com/LedgerHQ/ledger-live/commit/c68c3121b93d38567f31682c9a4b191f29db02a0) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - Pass through from currency if exists in location to demo 3
+
+- [#7573](https://github.com/LedgerHQ/ledger-live/pull/7573) [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752) Thanks [@liviuciulinaru](https://github.com/liviuciulinaru)! - [swap] setup demo3 flag and routes
+
+- [#7662](https://github.com/LedgerHQ/ledger-live/pull/7662) [`4485e37`](https://github.com/LedgerHQ/ledger-live/commit/4485e3792b6ad7517a923f220858e667dbc7c97a) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add more precise name for LLD Instances
+
+- [#7592](https://github.com/LedgerHQ/ledger-live/pull/7592) [`a354886`](https://github.com/LedgerHQ/ledger-live/commit/a354886e05e12b519f89d93cee079bbff3104723) Thanks [@Wozacosta](https://github.com/Wozacosta)! - fixes display of account unit during send
+
+- [#7734](https://github.com/LedgerHQ/ledger-live/pull/7734) [`255f035`](https://github.com/LedgerHQ/ledger-live/commit/255f035b8415eb09683f959e37593e1969f5911c) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add rare satoshis icons to ui package and a mapping inside LLD to use them
+
+- [#7715](https://github.com/LedgerHQ/ledger-live/pull/7715) [`f4bb881`](https://github.com/LedgerHQ/ledger-live/commit/f4bb881f79b38d2a1798933a4a5cd713167fad72) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: persistant gasOptions between evm chains creating crashes
+
+- [#7731](https://github.com/LedgerHQ/ledger-live/pull/7731) [`e1d6d7d`](https://github.com/LedgerHQ/ledger-live/commit/e1d6d7d72059db3db29c8968364c4d348398446b) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add vertical scroll inside optin prompt and correct variable name. Fix export account row from settings that was hidden when LS enabled
+
+- [#7585](https://github.com/LedgerHQ/ledger-live/pull/7585) [`aadad07`](https://github.com/LedgerHQ/ledger-live/commit/aadad0732479f99bf502378fd74805f5a6f842f4) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: render loader on result for startExchange
+
+- [#7663](https://github.com/LedgerHQ/ledger-live/pull/7663) [`1a5bcec`](https://github.com/LedgerHQ/ledger-live/commit/1a5bcecb79d6c29b895f5d2d317a7aec00013acf) Thanks [@valpinkman](https://github.com/valpinkman)! - Avoid running watchloop when LS ff is disabled
+
+- [#7709](https://github.com/LedgerHQ/ledger-live/pull/7709) [`1f74063`](https://github.com/LedgerHQ/ledger-live/commit/1f7406327583cb61944cab18023e966b5ac467aa) Thanks [@CremaFR](https://github.com/CremaFR)! - btc and evm fee drawer display amount errors when editing fees too high
+
+- [#7711](https://github.com/LedgerHQ/ledger-live/pull/7711) [`e5c578b`](https://github.com/LedgerHQ/ledger-live/commit/e5c578b7be3fe0653bc7fced49eb5713b134f741) Thanks [@CremaFR](https://github.com/CremaFR)! - fix setTransaction fee drawer call to check error status
+
+- [#7660](https://github.com/LedgerHQ/ledger-live/pull/7660) [`9c584a0`](https://github.com/LedgerHQ/ledger-live/commit/9c584a08063dedc4eb4baeb3b0e719acf98a2087) Thanks [@sergiubreban](https://github.com/sergiubreban)! - removes old manifest id for buy-sell app
+
+- [#7527](https://github.com/LedgerHQ/ledger-live/pull/7527) [`c7b5135`](https://github.com/LedgerHQ/ledger-live/commit/c7b5135a2a81311fba8a706790ae3c7dadd4a32a) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix firmware update for old firmware versions
+
+- [#7657](https://github.com/LedgerHQ/ledger-live/pull/7657) [`2359a8e`](https://github.com/LedgerHQ/ledger-live/commit/2359a8e34fbe1a1ac073b6d18d66d2942a5dd817) Thanks [@valpinkman](https://github.com/valpinkman)! - Prevent the use of webp for Custom Lock Screen
+
+- [#7680](https://github.com/LedgerHQ/ledger-live/pull/7680) [`714a096`](https://github.com/LedgerHQ/ledger-live/commit/714a096a9310c0f502381f8ec0869c6a662b6ec9) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: uses native segwit empty address to compute btc fees
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- [#7555](https://github.com/LedgerHQ/ledger-live/pull/7555) [`aa9110f`](https://github.com/LedgerHQ/ledger-live/commit/aa9110feeb862d4c340e698950d0133d0eb1efb1) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Custom lock screen: disallow selection of gifs
+
+- [#7610](https://github.com/LedgerHQ/ledger-live/pull/7610) [`08fd8b4`](https://github.com/LedgerHQ/ledger-live/commit/08fd8b4c2150a32a72f2b943d1ef76724a1e2544) Thanks [@mwiercinska](https://github.com/mwiercinska)! - Add locale and ticker query params for buy/sell
+
+- [#7736](https://github.com/LedgerHQ/ledger-live/pull/7736) [`644332f`](https://github.com/LedgerHQ/ledger-live/commit/644332f58790fb89375b9ca8a4b58e5f1613c14f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Fix Animation Color
+
+- [#7629](https://github.com/LedgerHQ/ledger-live/pull/7629) [`81468af`](https://github.com/LedgerHQ/ledger-live/commit/81468af073af1ccdeb3fdbcf6b2c998cebc68ab5) Thanks [@mwiercinska](https://github.com/mwiercinska)! - add translation for back to quote CTA in WebPTXPlayer
+
+- [#7700](https://github.com/LedgerHQ/ledger-live/pull/7700) [`55f40b1`](https://github.com/LedgerHQ/ledger-live/commit/55f40b1c9bbc91ba7b4aada849c94987546bad75) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update analytics
+
+- [#7690](https://github.com/LedgerHQ/ledger-live/pull/7690) [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57) Thanks [@thesan](https://github.com/thesan)! - Refresh ledger sync QR code on expiration
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- [#7654](https://github.com/LedgerHQ/ledger-live/pull/7654) [`351cef9`](https://github.com/LedgerHQ/ledger-live/commit/351cef9caa68c1f88d1d709206ad5c3d5f22998b) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Minor copy update for LedgerSync
+
+- [#7679](https://github.com/LedgerHQ/ledger-live/pull/7679) [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix removal of custom lock screen on LLD
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`87c160d`](https://github.com/LedgerHQ/ledger-live/commit/87c160d855b512d5a0394eaee7626e2b8cd431ee), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`d60a022`](https://github.com/LedgerHQ/ledger-live/commit/d60a02238db9ed16142de4c1874e26d27aaaa98c), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`ef99222`](https://github.com/LedgerHQ/ledger-live/commit/ef99222a5adcd9732d06600bc875309c440e084f), [`e5419de`](https://github.com/LedgerHQ/ledger-live/commit/e5419ded434a3f6a203c0195932b5b846fec0e2c), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`8e0ac04`](https://github.com/LedgerHQ/ledger-live/commit/8e0ac04ac8cdaaee59633ebdf219e5dcf44a10df), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8ac662`](https://github.com/LedgerHQ/ledger-live/commit/c8ac662e6f88349187f802741e14c3d5fb67cddb), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`d213d81`](https://github.com/LedgerHQ/ledger-live/commit/d213d8122647d559b7a0f44e2beffa5e39c3249b), [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1), [`e7db725`](https://github.com/LedgerHQ/ledger-live/commit/e7db72552042ff4dd85bec236f6bd083fa3da533), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0-next.0
+ - @ledgerhq/trustchain@0.3.0-next.0
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/hw-transport-node-speculos-http@6.29.3-next.0
+ - @ledgerhq/hw-transport-http@6.30.3-next.0
+ - @ledgerhq/coin-bitcoin@0.8.0-next.0
+ - @ledgerhq/coin-evm@2.2.0-next.0
+ - @ledgerhq/domain-service@1.2.4-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/live-countervalues@0.2.5-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-countervalues-react@0.2.5-next.0
+ - @ledgerhq/react-ui@0.16.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/live-wallet@0.6.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/hw-trustchain@0.1.5-next.0
+ - @ledgerhq/coin-cosmos@0.1.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+ - @ledgerhq/hw-transport@6.31.3-next.0
+ - @ledgerhq/hw-transport-node-hid-singleton@6.31.4-next.0
+ - @ledgerhq/hw-transport-vault@1.3.3-next.0
+ - @ledgerhq/live-nft@0.4.5-next.0
+ - @ledgerhq/live-nft-react@0.4.5-next.0
+
## 2.85.1
### Patch Changes
diff --git a/apps/ledger-live-desktop/RELEASE_NOTES.md b/apps/ledger-live-desktop/RELEASE_NOTES.md
index 8ca3d58a8056..cdcc3ffd2b5d 100644
--- a/apps/ledger-live-desktop/RELEASE_NOTES.md
+++ b/apps/ledger-live-desktop/RELEASE_NOTES.md
@@ -1,3 +1,19 @@
+# 2.86.0
+
+### 🚀 Features
+
+You can now swap cross-chain with Exodus as a new provider.
+
+We’ve added support for TON tokens.
+
+FIL tokens are now also supported but limited to f0, f4 & 0x addresses.
+
+### 🌷 Improvements
+
+We’ve made it easier to reach your favorite provider quickly using the Buy flow.
+
+MATIC has been renamed to POL across the platform.
+
# 2.85.1
Some Windows users reported issues with device interactions. This has been fixed.
diff --git a/apps/ledger-live-desktop/__mocks__/@polkadot/util-crypto.js b/apps/ledger-live-desktop/__mocks__/@polkadot/util-crypto.js
new file mode 100644
index 000000000000..f053ebf7976e
--- /dev/null
+++ b/apps/ledger-live-desktop/__mocks__/@polkadot/util-crypto.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/apps/ledger-live-desktop/__mocks__/@polkadot/x-fetch.js b/apps/ledger-live-desktop/__mocks__/@polkadot/x-fetch.js
new file mode 100644
index 000000000000..f053ebf7976e
--- /dev/null
+++ b/apps/ledger-live-desktop/__mocks__/@polkadot/x-fetch.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/apps/ledger-live-desktop/__mocks__/@polkadot/x-textdecoder.js b/apps/ledger-live-desktop/__mocks__/@polkadot/x-textdecoder.js
new file mode 100644
index 000000000000..b297defd04d1
--- /dev/null
+++ b/apps/ledger-live-desktop/__mocks__/@polkadot/x-textdecoder.js
@@ -0,0 +1,3 @@
+module.exports = {
+ TextDecoder: global.TextDecoder,
+};
diff --git a/apps/ledger-live-desktop/__mocks__/@polkadot/x-textencoder.js b/apps/ledger-live-desktop/__mocks__/@polkadot/x-textencoder.js
new file mode 100644
index 000000000000..e4bca30f783b
--- /dev/null
+++ b/apps/ledger-live-desktop/__mocks__/@polkadot/x-textencoder.js
@@ -0,0 +1,3 @@
+module.exports = {
+ TextEncoder: global.TextEncoder,
+};
diff --git a/apps/ledger-live-desktop/__mocks__/@polkadot/x-ws.js b/apps/ledger-live-desktop/__mocks__/@polkadot/x-ws.js
new file mode 100644
index 000000000000..f053ebf7976e
--- /dev/null
+++ b/apps/ledger-live-desktop/__mocks__/@polkadot/x-ws.js
@@ -0,0 +1 @@
+module.exports = {};
diff --git a/apps/ledger-live-desktop/deeplinks-test-page.html b/apps/ledger-live-desktop/deeplinks-test-page.html
index f26f973370a7..1a3746c305f9 100644
--- a/apps/ledger-live-desktop/deeplinks-test-page.html
+++ b/apps/ledger-live-desktop/deeplinks-test-page.html
@@ -226,11 +226,15 @@
Discover
🔗
-
+
+
Earn
diff --git a/apps/ledger-live-desktop/jest.config.js b/apps/ledger-live-desktop/jest.config.js
index 663937af369a..4870e0403a02 100644
--- a/apps/ledger-live-desktop/jest.config.js
+++ b/apps/ledger-live-desktop/jest.config.js
@@ -11,6 +11,7 @@ const testPathIgnorePatterns = [
".yalc",
"cli/",
"test-helpers/",
+ "src/.*/shared\\.(ts|tsx)$",
];
const moduleNameMapper = {
@@ -23,6 +24,8 @@ const moduleNameMapper = {
uuid: require.resolve("uuid"),
"react-spring": require.resolve("react-spring"),
"@braze/web-sdk": require.resolve("@braze/web-sdk"),
+ "@polkadot/x-fetch": "/__mocks__/x-fetch.js",
+ "@polkadot/x-ws": "/__mocks__/x-ws.js",
};
const commonConfig = {
@@ -37,7 +40,7 @@ const commonConfig = {
},
moduleNameMapper,
testPathIgnorePatterns,
- setupFiles: ["jest-canvas-mock"],
+ setupFiles: ["jest-canvas-mock", "./jest.polyfills.js"],
setupFilesAfterEnv: ["/tests/jestSetup.js"],
extensionsToTreatAsEsm: [".ts", ".tsx", ".jsx"],
transform: {
@@ -56,11 +59,16 @@ const commonConfig = {
moduleDirectories: ["node_modules", "./tests"],
modulePaths: [compilerOptions.baseUrl],
resolver: "/scripts/resolver.js",
+ testEnvironmentOptions: {
+ customExportConditions: [""],
+ },
};
module.exports = {
collectCoverageFrom: ["src/**/*.{ts,tsx}", "!src/**/*.test.{ts,tsx}", "!src/**/*.spec.{ts,tsx}"],
coverageReporters: ["json", "lcov", "json-summary"],
+ silent: false,
+ verbose: true,
projects: [
{
...commonConfig,
@@ -69,6 +77,7 @@ module.exports = {
...testPathIgnorePatterns,
"(/__tests__/.*|(\\.|/)react\\.test|spec)\\.tsx",
],
+ testMatch: ["**/src/**/*.test.(ts|tsx)"],
},
{
...commonConfig,
diff --git a/apps/ledger-live-desktop/jest.polyfills.js b/apps/ledger-live-desktop/jest.polyfills.js
new file mode 100644
index 000000000000..2b1943680bdb
--- /dev/null
+++ b/apps/ledger-live-desktop/jest.polyfills.js
@@ -0,0 +1,23 @@
+/* eslint-disable @typescript-eslint/no-var-requires */
+/* eslint-disable no-undef */
+const { TextDecoder, TextEncoder } = require("node:util");
+const { ReadableStream } = require("node:stream/web");
+
+Object.defineProperties(globalThis, {
+ TextDecoder: { value: TextDecoder },
+ TextEncoder: { value: TextEncoder },
+ ReadableStream: { value: ReadableStream },
+});
+
+const { Blob, File } = require("node:buffer");
+const { fetch, Headers, FormData, Request, Response } = require("undici");
+
+Object.defineProperties(globalThis, {
+ fetch: { value: fetch, writable: true },
+ Blob: { value: Blob },
+ File: { value: File },
+ Headers: { value: Headers },
+ FormData: { value: FormData },
+ Request: { value: Request },
+ Response: { value: Response },
+});
diff --git a/apps/ledger-live-desktop/package.json b/apps/ledger-live-desktop/package.json
index bd03256008ed..97db33db1aa3 100644
--- a/apps/ledger-live-desktop/package.json
+++ b/apps/ledger-live-desktop/package.json
@@ -13,7 +13,7 @@
"license": "MIT",
"private": true,
"main": "./.webpack/main.bundle.js",
- "version": "2.85.1",
+ "version": "2.86.0",
"scripts": {
"start:prod": "electron ./.webpack/main.bundle.js",
"start": "cross-env NODE_ENV=development node ./tools/main.js",
@@ -25,7 +25,7 @@
"lint:ci": "zx scripts/ci-lint.mjs",
"lint:fix": "eslint src tools static tests --ext .js,.jsx,.json,.ts,.tsx --fix",
"prettier": "prettier --write \"{src,tools,tests}/**/*.{js,jsx,json,ts,tsx}\"",
- "prettier:check": "prettier -c \"{src,tools}/**/*.{js,jsx,json,ts,tsx}\"",
+ "prettier:check": "prettier -c \"{src,tools,tests}/**/*.{js,jsx,json,ts,tsx}\"",
"preinstall-deps": "rimraf node_modules/paralleljs/package.json",
"install-deps": "electron-builder install-app-deps",
"postinstall": "node ./scripts/post-install.js",
@@ -36,7 +36,7 @@
"pre-build": "node ./tools/dist --pre -v",
"release": "node ./tools/dist --release -v",
"test": "pnpm test:jest:coverage && pnpm test:playwright",
- "test:jest": "jest src --maxWorkers=50%",
+ "test:jest": "jest --maxWorkers=50%",
"test:jest:coverage": "pnpm test:jest --ci --coverage",
"test:playwright:setup": "playwright install chromium",
"test:playwright": "playwright test --config=tests/playwright.config.ts --project=mocked_tests",
@@ -53,6 +53,7 @@
"dependencies": {
"@braze/web-sdk": "^4.6.3",
"@ledgerhq/coin-bitcoin": "workspace:^",
+ "@ledgerhq/coin-cosmos": "workspace:^",
"@ledgerhq/coin-evm": "workspace:^",
"@ledgerhq/coin-framework": "workspace:^",
"@ledgerhq/devices": "workspace:*",
@@ -101,12 +102,14 @@
"electron-updater": "^6.1.7",
"firebase": "^9.6.6",
"focus-trap": "^6.6.1",
+ "framer-motion": "^11.3.28",
"fuse.js": "^6.6.2",
"i18next": "^23.4.4",
"invariant": "^2.2.4",
"json-rpc-2.0": "^0.2.19",
"jsqr": "^1.4.0",
"lodash": "^4.17.21",
+ "msw": "^2.3.2",
"prando": "^5.1.2",
"prop-types": "^15.8.1",
"qrcode": "^1.4.4",
@@ -146,6 +149,7 @@
"tippy.js": "^6.3.7",
"tree-kill": "^1.2.2",
"uncontrollable": "^7.2.1",
+ "undici": "^6.19.2",
"uuid": "^9.0.0",
"winston": "^3.2.1",
"winston-transport": "^4.3.0",
@@ -198,7 +202,7 @@
"@types/write-file-atomic": "^4.0.0",
"@vitejs/plugin-react": "^3.1.0",
"allure-playwright": "2.15.1",
- "axios": "1.3.4",
+ "axios": "1.7.3",
"chalk": "^4.1.2",
"cross-env": "^7.0.3",
"debug": "^4.3.4",
@@ -215,6 +219,7 @@
"jest-environment-jsdom": "^29.7.0",
"listr": "^0.14.3",
"listr-verbose-renderer": "^0.6.0",
+ "nock": "^13.0.5",
"prebuild-install": "^7.1.1",
"react-refresh": "^0.14.0",
"react-test-renderer": "^18.2.0",
@@ -226,4 +231,4 @@
"vite-plugin-electron": "0.4.9",
"yargs": "^17.0.0"
}
-}
+}
\ No newline at end of file
diff --git a/apps/ledger-live-desktop/scripts/resolver.js b/apps/ledger-live-desktop/scripts/resolver.js
index bfe9490abeb7..66829ecebc34 100644
--- a/apps/ledger-live-desktop/scripts/resolver.js
+++ b/apps/ledger-live-desktop/scripts/resolver.js
@@ -1,29 +1,32 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
module.exports = (path, options) => {
// Call the defaultResolver, so we leverage its cache, error handling, etc.
return options.defaultResolver(path, {
...options,
// Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb)
packageFilter: pkg => {
- // This is a workaround for https://github.com/uuidjs/uuid/pull/616
- //
- // jest-environment-jsdom 28+ tries to use browser exports instead of default exports,
- // but uuid only offers an ESM browser export and not a CommonJS one. Jest does not yet
- // support ESM modules natively, so this causes a Jest error related to trying to parse
- // "export" syntax.
- //
- // This workaround prevents Jest from considering uuid's module-based exports at all;
- // it falls back to uuid's CommonJS+node "main" property.
- //
- // Once we're able to migrate our Jest config to ESM and a browser crypto
- // implementation is available for the browser+ESM version of uuid to use (eg, via
- // https://github.com/jsdom/jsdom/pull/3352 or a similar polyfill), this can go away.
- if (pkg.name === "uuid") {
+ const pkgNamesToTarget = new Set([
+ "rxjs",
+ "@firebase/auth",
+ "@firebase/storage",
+ "@firebase/functions",
+ "@firebase/database",
+ "@firebase/auth-compat",
+ "@firebase/database-compat",
+ "@firebase/app-compat",
+ "@firebase/firestore",
+ "@firebase/firestore-compat",
+ "@firebase/messaging",
+ "@firebase/util",
+ "firebase",
+ "uuid",
+ ]);
+
+ if (pkgNamesToTarget.has(pkg.name)) {
+ // console.log('>>>', pkg.name)
delete pkg["exports"];
delete pkg["module"];
}
+
return pkg;
},
});
diff --git a/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts b/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts
index 418f4e80f3d1..39a0d9048e20 100644
--- a/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts
+++ b/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts
@@ -42,7 +42,6 @@ setSupportedCurrencies([
"qtum",
"bitcoin_gold",
"komodo",
- "pivx",
"zencash",
"bitcoin_testnet",
"ethereum_sepolia",
diff --git a/apps/ledger-live-desktop/src/main/mergeAllLogs.test.ts b/apps/ledger-live-desktop/src/main/mergeAllLogs.test.ts
new file mode 100644
index 000000000000..b479b4e532a7
--- /dev/null
+++ b/apps/ledger-live-desktop/src/main/mergeAllLogs.test.ts
@@ -0,0 +1,158 @@
+import { Log } from "./logger";
+import { mergeAllLogs, mergeAllLogsJSON, MergeResult } from "./mergeAllLogs";
+
+const internalLogsChronological: Array = [
+ { date: new Date(1), message: "Internal log 1" } as Log,
+ { date: new Date(2), message: "Internal log 2" } as Log,
+ { date: new Date(2), message: "Internal log 3 (same date as internal 2)" } as Log,
+ { date: new Date(4), message: "Internal log 4" } as Log,
+ { date: new Date(4), message: "Internal log 5 (same date as internal 4)" } as Log,
+];
+
+const rendererLogsChronological: Array<{ timestamp: string; message: string }> = [
+ { timestamp: new Date(1).toISOString(), message: "Renderer log 1 (same date as internal 1)" },
+ { timestamp: new Date(3).toISOString(), message: "Renderer log 2" },
+ { timestamp: new Date(3).toISOString(), message: "Renderer log 3" },
+ { timestamp: new Date(4).toISOString(), message: "Renderer log 4 (same date as internal 4)" },
+ { timestamp: new Date(5).toISOString(), message: "Renderer log 5" },
+];
+
+const expectedMergedLogs: MergeResult = [
+ {
+ message:
+ "Exporting logs: Only the last 8 logs are saved. To change this limit, set the EXPORT_MAX_LOGS env variable.",
+ logIndex: 0,
+ pname: "electron-main",
+ timestamp: "1970-01-01T00:00:00.000Z",
+ type: "exportLogsMeta",
+ },
+ {
+ timestamp: "1970-01-01T00:00:00.002Z",
+ message: "Internal log 2",
+ pname: "electron-internal",
+ logIndex: 2,
+ },
+ {
+ timestamp: "1970-01-01T00:00:00.002Z",
+ message: "Internal log 3 (same date as internal 2)",
+ pname: "electron-internal",
+ logIndex: 3,
+ },
+ {
+ message: "Renderer log 2",
+ pname: "electron-renderer",
+ timestamp: "1970-01-01T00:00:00.003Z",
+ logIndex: 4,
+ },
+ {
+ message: "Renderer log 3",
+ pname: "electron-renderer",
+ timestamp: "1970-01-01T00:00:00.003Z",
+ logIndex: 5,
+ },
+ {
+ message: "Renderer log 4 (same date as internal 4)",
+ pname: "electron-renderer",
+ timestamp: "1970-01-01T00:00:00.004Z",
+ logIndex: 6,
+ },
+ {
+ timestamp: "1970-01-01T00:00:00.004Z",
+ message: "Internal log 4",
+ pname: "electron-internal",
+ logIndex: 7,
+ },
+ {
+ timestamp: "1970-01-01T00:00:00.004Z",
+ message: "Internal log 5 (same date as internal 4)",
+ pname: "electron-internal",
+ logIndex: 8,
+ },
+ {
+ message: "Renderer log 5",
+ pname: "electron-renderer",
+ timestamp: "1970-01-01T00:00:00.005Z",
+ logIndex: 9,
+ },
+];
+
+const expectedMergedLogsJSON = `\
+[
+ {
+ "logIndex": 0,
+ "timestamp": "1970-01-01T00:00:00.000Z",
+ "pname": "electron-main",
+ "type": "exportLogsMeta",
+ "message": "Exporting logs: Only the last 8 logs are saved. To change this limit, set the EXPORT_MAX_LOGS env variable."
+ },
+ {
+ "logIndex": 2,
+ "timestamp": "1970-01-01T00:00:00.002Z",
+ "pname": "electron-internal",
+ "message": "Internal log 2"
+ },
+ {
+ "logIndex": 3,
+ "timestamp": "1970-01-01T00:00:00.002Z",
+ "pname": "electron-internal",
+ "message": "Internal log 3 (same date as internal 2)"
+ },
+ {
+ "logIndex": 4,
+ "timestamp": "1970-01-01T00:00:00.003Z",
+ "pname": "electron-renderer",
+ "message": "Renderer log 2"
+ },
+ {
+ "logIndex": 5,
+ "timestamp": "1970-01-01T00:00:00.003Z",
+ "pname": "electron-renderer",
+ "message": "Renderer log 3"
+ },
+ {
+ "logIndex": 6,
+ "timestamp": "1970-01-01T00:00:00.004Z",
+ "pname": "electron-renderer",
+ "message": "Renderer log 4 (same date as internal 4)"
+ },
+ {
+ "logIndex": 7,
+ "timestamp": "1970-01-01T00:00:00.004Z",
+ "pname": "electron-internal",
+ "message": "Internal log 4"
+ },
+ {
+ "logIndex": 8,
+ "timestamp": "1970-01-01T00:00:00.004Z",
+ "pname": "electron-internal",
+ "message": "Internal log 5 (same date as internal 4)"
+ },
+ {
+ "logIndex": 9,
+ "timestamp": "1970-01-01T00:00:00.005Z",
+ "pname": "electron-renderer",
+ "message": "Renderer log 5"
+ }
+]`;
+
+describe("mergeAllLogs", () => {
+ it("should merge logs from the renderer process and logs recorded from the internal process", () => {
+ const mergedLogs = mergeAllLogs(rendererLogsChronological, internalLogsChronological, 8);
+
+ console.log("mergedLogs", mergedLogs);
+
+ expect(mergedLogs).toEqual(expectedMergedLogs);
+ });
+});
+
+describe("mergeAllLogsJSON", () => {
+ it("return the merged logs with their keys properly ordered (logIndex, then date, then process, then message)", () => {
+ const mergedLogsJSON = mergeAllLogsJSON(
+ rendererLogsChronological,
+ internalLogsChronological,
+ 8,
+ );
+
+ expect(mergedLogsJSON).toEqual(expectedMergedLogsJSON);
+ });
+});
diff --git a/apps/ledger-live-desktop/src/main/mergeAllLogs.ts b/apps/ledger-live-desktop/src/main/mergeAllLogs.ts
new file mode 100644
index 000000000000..40d865af44c6
--- /dev/null
+++ b/apps/ledger-live-desktop/src/main/mergeAllLogs.ts
@@ -0,0 +1,129 @@
+import { Log } from "./logger";
+
+/**
+ * Custom JSON.stringify function that orders the keys in a specified order.
+ */
+export function customStringify(obj: unknown) {
+ const orderedKeys = [
+ "logIndex",
+ "timestamp",
+ "pname",
+ "type",
+ "level",
+ "id",
+ "message",
+ "data",
+ "context",
+ ];
+
+ return JSON.stringify(
+ obj,
+ (_, value) => {
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
+ const orderedObject: Record = {};
+
+ // Add the keys in the specified order
+ for (const key of orderedKeys) {
+ if (key in value) {
+ orderedObject[key] = value[key];
+ }
+ }
+
+ // Add the remaining keys
+ for (const key in value) {
+ if (!(key in orderedObject)) {
+ orderedObject[key] = value[key];
+ }
+ }
+
+ return orderedObject;
+ }
+ return value;
+ },
+ 2,
+ );
+}
+
+export type MergeResult = Array<
+ | ({
+ logIndex: number;
+ /** Process name */
+ pname: string;
+ /** Date formatted in ISO string (this is badly named but we're keeping the legacy name for compatibility with the logs viewer) */
+ timestamp: string;
+ } & Record)
+ | string
+>;
+
+/**
+ * Merges logs from the renderer process and logs recorded from the internal process.
+ * The logs are ordered by date and the most recent logs are kept.
+ *
+ * @param rendererLogsChronological Logs from the renderer process, ordered by date.
+ * @param internalLogsChronological Logs from the internal process, ordered by date.
+ * @param maxLogCount The maximum number of logs to keep.
+ * @returns The merged logs, ordered by date.
+ */
+export function mergeAllLogs(
+ rendererLogsChronological: Array<{ timestamp: string }>,
+ internalLogsChronological: Array,
+ maxLogCount: number,
+): MergeResult {
+ console.log(
+ `Saving ${rendererLogsChronological.length} logs from the renderer process and ${internalLogsChronological.length} logs from the internal process`,
+ );
+
+ function compareLogs(
+ a: { timestamp: string; pname: string; originalIndex: number },
+ b: { timestamp: string; pname: string; originalIndex: number },
+ ) {
+ const dateCompared = a.timestamp.localeCompare(b.timestamp);
+ if (dateCompared !== 0 || a.pname !== b.pname) return dateCompared;
+ return a.originalIndex - b.originalIndex;
+ }
+
+ const allLogs: MergeResult = [
+ ...rendererLogsChronological.map((log, index) => ({
+ ...log,
+ pname: "electron-renderer",
+ originalIndex: index, // This is used to keep the order of the logs in case some logs in that collection have the same date
+ })),
+ ...internalLogsChronological.map((log, index) => {
+ const { date, ...rest } = log;
+ return {
+ ...rest,
+ pname: "electron-internal",
+ timestamp: typeof date === "string" ? date : date.toISOString(),
+ originalIndex: index,
+ };
+ }),
+ ]
+ .sort(compareLogs)
+ .map((log, index) => {
+ const { originalIndex, ...rest } = log;
+ return { ...rest, logIndex: index };
+ })
+ .slice(-maxLogCount);
+
+ if (rendererLogsChronological.length + internalLogsChronological.length > maxLogCount) {
+ allLogs.unshift({
+ message: `Exporting logs: Only the last ${maxLogCount} logs are saved. To change this limit, set the EXPORT_MAX_LOGS env variable.`,
+ logIndex: 0,
+ type: "exportLogsMeta",
+ pname: "electron-main",
+ timestamp: new Date(0).toISOString(),
+ });
+ }
+
+ return allLogs;
+}
+
+export function mergeAllLogsJSON(
+ rendererLogsChronological: Array<{ timestamp: string }>,
+ internalLogsChronological: Array,
+ maxLogCount: number,
+) {
+ return customStringify(
+ mergeAllLogs(rendererLogsChronological, internalLogsChronological, maxLogCount),
+ );
+}
diff --git a/apps/ledger-live-desktop/src/main/setup.ts b/apps/ledger-live-desktop/src/main/setup.ts
index 196d9128d9d6..94f2132cfacc 100644
--- a/apps/ledger-live-desktop/src/main/setup.ts
+++ b/apps/ledger-live-desktop/src/main/setup.ts
@@ -7,8 +7,9 @@ import { log } from "@ledgerhq/logs";
import fs from "fs/promises";
import updater from "./updater";
import path from "path";
+import { mergeAllLogsJSON } from "./mergeAllLogs";
import { InMemoryLogger } from "./logger";
-import { setEnvUnsafe } from "@ledgerhq/live-env";
+import { getEnv, setEnvUnsafe } from "@ledgerhq/live-env";
/**
* Sets env variables for the main process.
@@ -36,31 +37,26 @@ ipcMain.handle(
async (_event, path: Electron.SaveDialogReturnValue, rendererLogsStr: string) => {
if (!path.canceled && path.filePath) {
const inMemoryLogger = InMemoryLogger.getLogger();
- const internalLogs = inMemoryLogger.getLogs();
+ const internalLogsChronological = inMemoryLogger.getLogs().reverse(); // The logs are in reverse order.
// The deserialization would have been done internally by electron if `rendererLogs` was passed directly as a JS object/array.
// But it avoids certain issues with the serialization/deserialization done by electron.
- let rendererLogs: unknown[] = [];
+ let rendererLogsChronological: Array<{ timestamp: string }> = [];
try {
- rendererLogs = JSON.parse(rendererLogsStr) as unknown[];
+ rendererLogsChronological = JSON.parse(rendererLogsStr).reverse(); // The logs are in reverse order.
} catch (error) {
console.error("Error while parsing logs from the renderer process", error);
return;
}
- console.log(
- `Saving ${rendererLogs.length} logs from the renderer process and ${internalLogs.length} logs from the internal process`,
+ fs.writeFile(
+ path.filePath,
+ mergeAllLogsJSON(
+ rendererLogsChronological,
+ internalLogsChronological,
+ getEnv("EXPORT_MAX_LOGS"),
+ ),
);
-
- // Merging according to a `date` (internal logs) / `timestamp` (most of renderer logs) does not seem necessary.
- // Simply pushes all the internal logs after the renderer logs.
- // Note: this is not respecting the `EXPORT_MAX_LOGS` env var, but this is fine.
- rendererLogs.push(
- { type: "logs-separator", message: "Logs coming from the internal process" },
- ...internalLogs,
- );
-
- fs.writeFile(path.filePath, JSON.stringify(rendererLogs, null, 2));
} else {
console.warn("No path given to save logs");
}
diff --git a/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts b/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts
index 75c87257d00f..befe1ce2f99a 100644
--- a/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts
+++ b/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts
@@ -1,10 +1,11 @@
import { IconsLegacy } from "@ledgerhq/react-ui";
import { openModal } from "~/renderer/actions/modals";
+import { CollectibleType } from "LLD/features/Collectibles/types/Collectibles";
+import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collectibles";
import { Account } from "@ledgerhq/types-live";
import { Dispatch } from "redux";
import { TFunction } from "i18next";
import { RouteComponentProps } from "react-router-dom";
-import { CollectibleType, CollectibleTypeEnum } from "LLD/features/Collectibles/types/Collectibles";
type Props = {
account: Account;
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx
index c388a185bccc..c2e2e237a8c7 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useCommonLogic.tsx
@@ -30,7 +30,7 @@ export const useAnalyticsOptInPrompt = ({ entryPoint }: Props) => {
const dispatch = useDispatch();
- const [isAnalitycsOptInPromptOpened, setIsAnalitycsOptInPromptOpened] = useState(false);
+ const [isAnalyticsOptInPromptOpened, setIsAnalyticsOptInPromptOpened] = useState(false);
const [nextStep, setNextStep] = useState<(() => void) | null>(null);
const flow = trackingKeysByFlow?.[entryPoint];
@@ -45,12 +45,12 @@ export const useAnalyticsOptInPrompt = ({ entryPoint }: Props) => {
[ABTestingVariants.variantB]: privacyPolicyUrl,
};
- const openAnalitycsOptInPrompt = useCallback(
+ const openAnalyticsOptInPrompt = useCallback(
(routePath: string, callBack: () => void) => {
- setIsAnalitycsOptInPromptOpened(true);
+ setIsAnalyticsOptInPromptOpened(true);
setNextStep(() => callBack);
},
- [setIsAnalitycsOptInPromptOpened],
+ [setIsAnalyticsOptInPromptOpened],
);
const isEntryPointIncludedInFlagParams = lldAnalyticsOptInPromptFlag?.params?.entryPoints
@@ -71,7 +71,7 @@ export const useAnalyticsOptInPrompt = ({ entryPoint }: Props) => {
);
const onSubmit = () => {
- setIsAnalitycsOptInPromptOpened(false);
+ setIsAnalyticsOptInPromptOpened(false);
dispatch(setHasSeenAnalyticsOptInPrompt(true));
if (entryPoint === EntryPoint.onboarding) {
nextStep?.();
@@ -80,8 +80,8 @@ export const useAnalyticsOptInPrompt = ({ entryPoint }: Props) => {
};
const analyticsOptInPromptProps = {
- onClose: () => setIsAnalitycsOptInPromptOpened(false),
- isOpened: isAnalitycsOptInPromptOpened,
+ onClose: () => setIsAnalyticsOptInPromptOpened(false),
+ isOpened: isAnalyticsOptInPromptOpened,
entryPoint: entryPoint,
variant,
};
@@ -101,8 +101,8 @@ export const useAnalyticsOptInPrompt = ({ entryPoint }: Props) => {
};
return {
- openAnalitycsOptInPrompt,
- setIsAnalitycsOptInPromptOpened,
+ openAnalyticsOptInPrompt,
+ setIsAnalyticsOptInPromptOpened,
onSubmit,
analyticsOptInPromptProps,
isFeatureFlagsAnalyticsPrefDisplayed: isFlagEnabled,
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useDisplayOnPortfolio.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useDisplayOnPortfolio.tsx
index 5e16695df3b6..194ce8bba4ed 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useDisplayOnPortfolio.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/hooks/useDisplayOnPortfolio.tsx
@@ -5,7 +5,7 @@ import { EntryPoint } from "../types/AnalyticsOptInPromptNavigator";
export const useDisplayOnPortfolioAnalytics = () => {
const {
analyticsOptInPromptProps,
- setIsAnalitycsOptInPromptOpened,
+ setIsAnalyticsOptInPromptOpened,
isFeatureFlagsAnalyticsPrefDisplayed,
onSubmit,
} = useAnalyticsOptInPrompt({ entryPoint: EntryPoint.portfolio });
@@ -16,8 +16,8 @@ export const useDisplayOnPortfolioAnalytics = () => {
};
useEffect(() => {
- if (isFeatureFlagsAnalyticsPrefDisplayed) setIsAnalitycsOptInPromptOpened(true);
- }, [isFeatureFlagsAnalyticsPrefDisplayed, setIsAnalitycsOptInPromptOpened]);
+ if (isFeatureFlagsAnalyticsPrefDisplayed) setIsAnalyticsOptInPromptOpened(true);
+ }, [isFeatureFlagsAnalyticsPrefDisplayed, setIsAnalyticsOptInPromptOpened]);
return {
analyticsOptInPromptProps: extendedAnalyticsOptInPromptProps,
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantA/Main/index.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantA/Main/index.tsx
index 30e68c892a98..2bb02fa82510 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantA/Main/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantA/Main/index.tsx
@@ -19,7 +19,14 @@ const Main = ({ shouldWeTrack, handleOpenPrivacyPolicy }: MainProps) => {
return (
<>
-
+
handleOpenPrivacyPolicy(page)} />
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/Analytics/index.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/Analytics/index.tsx
index 86274d20b998..7349e6f958a5 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/Analytics/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/Analytics/index.tsx
@@ -39,7 +39,13 @@ const AnalyticsScreen = ({
return (
<>
-
+
handleOpenPrivacyPolicy(page)} />
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/PersonalRecommendations/index.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/PersonalRecommendations/index.tsx
index c8defc6e009b..7a4cdf46a773 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/PersonalRecommendations/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/PersonalRecommendations/index.tsx
@@ -33,7 +33,7 @@ const RecommandationsScreen = ({
return (
<>
-
+
handleOpenPrivacyPolicy(page)} />
diff --git a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/index.tsx b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/index.tsx
index 7ea8f9b8324f..dedde1a751ce 100644
--- a/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/AnalyticsOptInPrompt/screens/VariantB/index.tsx
@@ -22,7 +22,7 @@ const VariantB = ({ entryPoint, onSubmit, step, setStep }: VariantBProps) => {
});
return (
<>
-
+
{step === 0 ? (
void;
-};
-
-type ViewProps = {
- nftsInTheCollection: NftsInTheCollections[];
- account: Account;
- displayShowMore: boolean;
- onOpenGallery: () => void;
- onReceive: () => void;
- onOpenCollection: (collectionAddress: string) => void;
- onShowMore: () => void;
-};
+type ViewProps = ReturnType;
type NftItemProps = {
contract: string;
@@ -66,7 +54,7 @@ const NftItem: React.FC = ({
>
onClick(contract)}
media={{
@@ -152,8 +140,8 @@ function View({
);
}
-const NftCollection: React.FC = ({ account }) => {
- return ;
+const NftCollections: React.FC = ({ account }) => {
+ return ;
};
-export default NftCollection;
+export default NftCollections;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collection/useNftCollectionModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collections/useNftCollectionsModel.tsx
similarity index 87%
rename from apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collection/useNftCollectionModel.tsx
rename to apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collections/useNftCollectionsModel.tsx
index f65c37ead358..d14d62a8e132 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collection/useNftCollectionModel.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Collections/useNftCollectionsModel.tsx
@@ -1,5 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from "react";
-import { Account } from "@ledgerhq/types-live";
+import { Account, ProtoNFT } from "@ledgerhq/types-live";
import { useDispatch, useSelector } from "react-redux";
import { useHistory } from "react-router-dom";
import { openModal } from "~/renderer/actions/modals";
@@ -7,15 +7,24 @@ import { hiddenNftCollectionsSelector } from "~/renderer/reducers/settings";
import { nftsByCollections } from "@ledgerhq/live-nft/index";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import { isThresholdValid, useNftGalleryFilter } from "@ledgerhq/live-nft-react";
-import { NftsInTheCollections as NftsInTheCollectionsType } from "./index";
-import { filterHiddenCollections, mapCollectionsToStructure } from "../../utils/collectionUtils";
+import {
+ filterHiddenCollections,
+ mapCollectionsToStructure,
+} from "LLD/features/Collectibles/utils/collectionUtils";
+
+type NftsInTheCollections = {
+ contract: string;
+ nft: ProtoNFT;
+ nftsNumber: number;
+ onClick: (collectionAddress: string) => void;
+};
type Props = {
account: Account;
};
const INCREMENT = 5;
-export const useNftCollectionModel = ({ account }: Props) => {
+export const useNftCollectionsModel = ({ account }: Props) => {
const history = useHistory();
const dispatch = useDispatch();
const nftsFromSimplehashFeature = useFeature("nftsFromSimplehash");
@@ -70,7 +79,7 @@ export const useNftCollectionModel = ({ account }: Props) => {
[account.id, collections, hiddenNftCollections],
);
- const nftsInTheCollection: NftsInTheCollectionsType[] = useMemo(
+ const nftsInTheCollection: NftsInTheCollections[] = useMemo(
() =>
mapCollectionsToStructure(filteredCollections, numberOfVisibleCollections, onOpenCollection),
[filteredCollections, numberOfVisibleCollections, onOpenCollection],
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/CommonStyled/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/CommonStyled/index.tsx
new file mode 100644
index 000000000000..38a963cda32c
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/CommonStyled/index.tsx
@@ -0,0 +1,27 @@
+import styled from "styled-components";
+
+const Footer = styled.footer`
+ height: 24px;
+ margin-bottom: 24px;
+`;
+
+const SpinnerContainer = styled.div`
+ display: flex;
+ flex: 1;
+ align-items: center;
+ justify-content: center;
+ padding: 20px;
+`;
+const SpinnerBackground = styled.div`
+ background: ${p => p.theme.colors.palette.background.paper};
+ border-radius: 100%;
+ padding: 2px;
+ width: 24px;
+ height: 24px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border: 2px solid ${p => p.theme.colors.palette.background.paper};
+`;
+
+export { Footer, SpinnerBackground, SpinnerContainer };
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Gallery/DetailDrawer/Actions.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/DetailDrawer/Actions.tsx
similarity index 100%
rename from apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Gallery/DetailDrawer/Actions.tsx
rename to apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/DetailDrawer/Actions.tsx
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Gallery/DetailDrawer/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/DetailDrawer/index.tsx
similarity index 98%
rename from apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Gallery/DetailDrawer/index.tsx
rename to apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/DetailDrawer/index.tsx
index 7748d2d4f95e..de51b35cb188 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/Gallery/DetailDrawer/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/DetailDrawer/index.tsx
@@ -4,7 +4,7 @@ import { DetailDrawer } from "LLD/features/Collectibles/components/DetailDrawer"
import useNftDetailDrawer from "LLD/features/Collectibles/hooks/useNftDetailDrawer";
import useCollectibles from "LLD/features/Collectibles/hooks/useCollectibles";
import { NftsDetailDrawerProps } from "LLD/features/Collectibles/types/Nfts";
-import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/Collectibles";
+import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collectibles";
import Actions from "./Actions";
const NftDetailDrawer = ({ account, tokenId, isOpened, setIsOpened }: NftsDetailDrawerProps) => {
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/index.tsx
new file mode 100644
index 000000000000..57efa57bfc30
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/index.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import TokensList from "LLD/features/Collectibles/components/Gallery/TokenList";
+import { useTokensListModel } from "./useTokensListModel";
+import { BaseNftsProps } from "LLD/features/Collectibles/types/Collectibles";
+import NftDetailDrawer from "LLD/features/Collectibles/Nfts/components/DetailDrawer";
+
+type ViewProps = ReturnType;
+
+function View({
+ account,
+ formattedNfts,
+ isDrawerOpen,
+ nftIdToOpen,
+ setIsDrawerOpen,
+ onItemClick,
+}: ViewProps) {
+ return (
+ <>
+
+ {isDrawerOpen && (
+
+ )}
+ >
+ );
+}
+
+const NftTokensList: React.FC = ({ ...props }) => (
+
+);
+
+export default NftTokensList;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/useTokensListModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/useTokensListModel.tsx
new file mode 100644
index 000000000000..f0ee225494fe
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/components/TokensList/useTokensListModel.tsx
@@ -0,0 +1,59 @@
+import { TokensListProps } from "LLD/features/Collectibles/types/TokensList";
+import { useSelector } from "react-redux";
+import { getNFTsByListOfIds } from "~/renderer/reducers/accounts";
+import { State } from "~/renderer/reducers";
+import { useNftMetadataBatch } from "@ledgerhq/live-nft-react";
+import { FieldStatus } from "LLD/features/Collectibles/types/enum/DetailDrawer";
+import { BaseNftsProps } from "LLD/features/Collectibles/types/Collectibles";
+import { useMemo, useState } from "react";
+
+export const useTokensListModel = ({ nfts, account }: BaseNftsProps): TokensListProps => {
+ const nftsIdsList: string[] = Object.keys(
+ nfts.reduce((acc, nft) => ({ ...acc, [nft.id]: nft }), {}),
+ );
+
+ const nftsList = useSelector((state: State) =>
+ getNFTsByListOfIds(state, {
+ nftIds: nftsIdsList,
+ }),
+ );
+
+ const metadata = useNftMetadataBatch(
+ nftsList.map(nft => ({
+ contract: nft?.contract,
+ tokenId: nft?.tokenId,
+ currencyId: nft?.currencyId,
+ })),
+ );
+
+ const formattedNfts = useMemo(() => {
+ return metadata.map((meta, index) => ({
+ id: nftsList[index]?.tokenId || "",
+ metadata: meta.metadata,
+ nft: nftsList[index],
+ collectibleId: nftsList[index]?.id || "",
+ standard: nftsList[index]?.standard || "",
+ amount: nftsList[index]?.amount || "",
+ tokenName: meta.metadata?.nftName || meta.metadata?.tokenName || "",
+ previewUri: meta?.metadata?.medias.preview.uri || "",
+ mediaType: meta?.metadata?.medias.preview.mediaType || "",
+ isLoading: meta?.status === FieldStatus.Loading || meta?.status === FieldStatus.Queued,
+ }));
+ }, [metadata, nftsList]);
+
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
+ const [nftIdToOpen, setNftIdToOpen] = useState("");
+ const onItemClick = (id: string) => {
+ setNftIdToOpen(id);
+ setIsDrawerOpen(true);
+ };
+
+ return {
+ account: account,
+ formattedNfts: formattedNfts,
+ isDrawerOpen,
+ nftIdToOpen,
+ onItemClick,
+ setIsDrawerOpen,
+ };
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/index.tsx
new file mode 100644
index 000000000000..88805789eb45
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/index.tsx
@@ -0,0 +1,102 @@
+import React, { memo, useEffect, useState } from "react";
+import useNftCollectionModel from "./useNftCollectionModel";
+import { useTranslation } from "react-i18next";
+import TrackPage from "~/renderer/analytics/TrackPage";
+import Box from "~/renderer/components/Box/Box";
+import Button from "~/renderer/components/Button";
+import Text from "~/renderer/components/Text";
+import { Flex, Icons } from "@ledgerhq/react-ui";
+import { Skeleton, Media, CollectionName, TableLayout } from "LLD/features/Collectibles/components";
+import TokensList from "../../components/TokensList";
+import OperationsList from "~/renderer/components/OperationsList";
+import Spinner from "~/renderer/components/Spinner";
+import { TrackingPageCategory } from "LLD/features/Collectibles/types/enum/Tracking";
+import { Footer, SpinnerContainer, SpinnerBackground } from "../../components/CommonStyled";
+
+type ViewProps = ReturnType;
+
+function View({
+ isLoading,
+ account,
+ collectionAddress,
+ nfts,
+ metadata,
+ slicedNfts,
+ listFooterRef,
+ maxVisibleNFTs,
+ filterOperation,
+ onSend,
+}: ViewProps) {
+ const { t } = useTranslation();
+ const [areItemsLoading, setAreItemsLoading] = useState(false);
+
+ useEffect(() => {
+ setAreItemsLoading(maxVisibleNFTs < nfts.length);
+ }, [maxVisibleNFTs, nfts.length]);
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+ {t("NFT.gallery.collection.header.contract", {
+ contract: collectionAddress,
+ })}
+
+
+
+
+
+
+
+
+
+
+
+
+ {account && }
+
+
+
+ >
+ );
+}
+
+const NftCollection: React.FC = () => {
+ return ;
+};
+
+export default memo(NftCollection);
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/useNftCollectionModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/useNftCollectionModel.tsx
new file mode 100644
index 000000000000..003b7a375b9e
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Collection/useNftCollectionModel.tsx
@@ -0,0 +1,77 @@
+import { useNftMetadata } from "@ledgerhq/live-nft-react";
+import { nftsByCollections } from "@ledgerhq/live-nft/index";
+import { ProtoNFT, NFT, Operation } from "@ledgerhq/types-live";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { useHistory, useParams } from "react-router-dom";
+import { State } from "~/renderer/reducers";
+import { accountSelector } from "~/renderer/reducers/accounts";
+import { FieldStatus } from "LLD/features/Collectibles/types/enum/DetailDrawer";
+import { openModal } from "~/renderer/actions/modals";
+import { useOnScreen } from "LLD/hooks/useOnScreen";
+
+const useNftCollectionModel = () => {
+ const dispatch = useDispatch();
+ const history = useHistory();
+
+ const { id, collectionAddress } = useParams<{ id: string; collectionAddress: string }>();
+ const account = useSelector((state: State) => accountSelector(state, { accountId: id }));
+
+ const listFooterRef = useRef(null);
+ const [maxVisibleNFTs, setMaxVisibleNFTs] = useState(1);
+
+ const nfts = useMemo<(ProtoNFT | NFT)[]>(
+ () => (nftsByCollections(account?.nfts, collectionAddress) as (ProtoNFT | NFT)[]) || [],
+ [account?.nfts, collectionAddress],
+ );
+
+ const [nft] = nfts;
+ const { status, metadata } = useNftMetadata(nft?.contract, nft?.tokenId, account?.currency.id);
+ const isLoading = useMemo(() => status === FieldStatus.Loading, [status]);
+
+ const onSend = useCallback(() => {
+ dispatch(
+ openModal("MODAL_SEND", {
+ account,
+ isNFTSend: true,
+ nftCollection: collectionAddress,
+ }),
+ );
+ }, [collectionAddress, dispatch, account]);
+
+ const filterOperation = (op: Operation) =>
+ !!op.nftOperations?.length &&
+ !!op.nftOperations.find(nftOp => nftOp?.contract === collectionAddress);
+
+ const updateMaxVisibleNtfs = () => setMaxVisibleNFTs(maxVisibleNFTs => maxVisibleNFTs + 5);
+
+ useOnScreen({
+ enabled: maxVisibleNFTs < nfts?.length,
+ onIntersect: updateMaxVisibleNtfs,
+ target: listFooterRef,
+ threshold: 0.5,
+ });
+
+ const slicedNfts = useMemo(() => nfts.slice(0, maxVisibleNFTs), [nfts, maxVisibleNFTs]);
+
+ useEffect(() => {
+ if (slicedNfts.length <= 0) {
+ history.push(`/account/${account?.id}/`);
+ }
+ }, [account?.id, history, slicedNfts.length]);
+
+ return {
+ isLoading,
+ collectionAddress,
+ account,
+ nfts,
+ metadata,
+ slicedNfts,
+ listFooterRef,
+ maxVisibleNFTs,
+ filterOperation,
+ onSend,
+ };
+};
+
+export default useNftCollectionModel;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/components/LazyCollection/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/components/LazyCollection/index.tsx
new file mode 100644
index 000000000000..a962f9a8fce5
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/components/LazyCollection/index.tsx
@@ -0,0 +1,67 @@
+import React, { memo, useEffect, useMemo } from "react";
+import { Box, Text } from "@ledgerhq/react-ui";
+import { CollectionName } from "LLD/features/Collectibles/components";
+import TokenList from "LLD/features/Collectibles/Nfts/components/TokensList";
+import { Account, ProtoNFT } from "@ledgerhq/types-live";
+import styled from "styled-components";
+
+type LazyCollectionProps = {
+ account: Account;
+ collections: [string, ProtoNFT[]][];
+ maxVisibleNFTs: number;
+ onSelectCollection: (contract: string) => void;
+ setIsLoading: (isLoading: boolean) => void;
+};
+
+const ClickableCollectionName = styled(Box)`
+ &:hover {
+ cursor: pointer;
+ }
+`;
+
+const LazyCollection: React.FC = ({
+ account,
+ collections,
+ maxVisibleNFTs,
+ onSelectCollection,
+ setIsLoading,
+}) => {
+ const renderedCollections = useMemo(() => {
+ const renderedCollections: JSX.Element[] = [];
+ let displayedNFTs = 0;
+ collections.forEach(([contract, nfts]: [string, ProtoNFT[]]) => {
+ if (displayedNFTs > maxVisibleNFTs) return;
+ renderedCollections.push(
+
+ onSelectCollection(contract)}>
+
+
+
+
+ {account && (
+ <>
+
+ >
+ )}
+
,
+ );
+ displayedNFTs += nfts.length;
+ });
+ return renderedCollections;
+ }, [collections, maxVisibleNFTs, account, onSelectCollection]);
+
+ useEffect(() => {
+ const isLoading = renderedCollections.length < collections.length;
+ setIsLoading(isLoading);
+ }, [collections.length, renderedCollections, setIsLoading]);
+
+ return <>{renderedCollections}>;
+};
+
+export default memo(LazyCollection);
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/index.tsx
new file mode 100644
index 000000000000..a7fc87cdc88e
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/index.tsx
@@ -0,0 +1,74 @@
+import React, { memo, useState } from "react";
+import TrackPage from "~/renderer/analytics/TrackPage";
+import useNftGalleryModel from "./useNftGalleryModel";
+import Box from "~/renderer/components/Box";
+import Text from "~/renderer/components/Text";
+import Button from "~/renderer/components/Button";
+import { Flex, Icons } from "@ledgerhq/react-ui";
+import { TableLayout } from "LLD/features/Collectibles/components";
+import { useTranslation } from "react-i18next";
+import { Account } from "@ledgerhq/types-live";
+import Spinner from "~/renderer/components/Spinner";
+import LazyCollection from "./components/LazyCollection";
+import { TrackingPageCategory } from "LLD/features/Collectibles/types/enum/Tracking";
+import { Footer, SpinnerContainer, SpinnerBackground } from "../../components/CommonStyled";
+
+type ViewProps = ReturnType;
+
+function View({
+ account,
+ listFooterRef,
+ maxVisibleNFTs,
+ collections,
+ onSelectCollection,
+ onSend,
+}: ViewProps) {
+ const { t } = useTranslation();
+ const [isLoading, setIsLoading] = useState(false);
+
+ return (
+
+
+
+
+
+ {t("NFT.gallery.title")}
+
+
+
+
+
+
+
+
+ );
+}
+
+const NftGallery: React.FC<{}> = () => ;
+
+export default memo(NftGallery);
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/useNftGalleryModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/useNftGalleryModel.tsx
new file mode 100644
index 000000000000..e22136ad0620
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Nfts/screens/Gallery/useNftGalleryModel.tsx
@@ -0,0 +1,103 @@
+import { useHistory, useParams } from "react-router-dom";
+import { useDispatch, useSelector } from "react-redux";
+import { State } from "~/renderer/reducers";
+import { accountSelector } from "~/renderer/reducers/accounts";
+import { hiddenNftCollectionsSelector } from "~/renderer/reducers/settings";
+import { useNftGalleryFilter, isThresholdValid } from "@ledgerhq/live-nft-react";
+import { nftsByCollections } from "@ledgerhq/live-nft";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { openModal } from "~/renderer/actions/modals";
+import { useOnScreen } from "LLD/hooks/useOnScreen";
+import useFeature from "@ledgerhq/live-common/featureFlags/useFeature";
+import { ChainsEnum } from "LLD/features/Collectibles/types/enum/Chains";
+
+const defaultNumberOfVisibleNfts = 10;
+
+const useNftGalleryModel = () => {
+ const dispatch = useDispatch();
+ const history = useHistory();
+ const { id } = useParams<{ id: string }>();
+
+ const nftsFromSimplehashFeature = useFeature("nftsFromSimplehash");
+ const threshold = nftsFromSimplehashFeature?.params?.threshold;
+
+ const listFooterRef = useRef(null);
+ const [maxVisibleNFTs, setMaxVisibleNFTs] = useState(defaultNumberOfVisibleNfts);
+
+ const { account, hiddenNftCollections } = useSelector((state: State) => ({
+ account: accountSelector(state, { accountId: id }),
+ hiddenNftCollections: hiddenNftCollectionsSelector(state),
+ }));
+
+ const { nfts, fetchNextPage, hasNextPage } = useNftGalleryFilter({
+ nftsOwned: account?.nfts || [],
+ addresses: account?.freshAddress || "",
+ chains: [account?.currency.id ?? ChainsEnum.ETHEREUM],
+ threshold: isThresholdValid(threshold) ? Number(threshold) : 75,
+ });
+
+ const collections = useMemo(() => {
+ const allNfts = nftsFromSimplehashFeature?.enabled ? nfts : account?.nfts;
+ return Object.entries(nftsByCollections(allNfts)).filter(
+ ([contract]) => !hiddenNftCollections.includes(`${account?.id}|${contract}`),
+ );
+ }, [account?.id, account?.nfts, hiddenNftCollections, nfts, nftsFromSimplehashFeature?.enabled]);
+
+ useEffect(() => {
+ if (collections.length < 1) {
+ history.push(`/account/${account?.id}/`);
+ }
+ }, [account?.id, history, collections.length]);
+
+ const onSend = useCallback(() => {
+ dispatch(openModal("MODAL_SEND", { account, isNFTSend: true }));
+ }, [dispatch, account]);
+
+ const onSelectCollection = useCallback(
+ (collectionAddress: string) => {
+ history.push({
+ pathname: `/account/${account?.id}/nft-collection/${collectionAddress}`,
+ });
+ },
+ [account?.id, history],
+ );
+
+ const updateMaxVisibleNtfs = useCallback(() => {
+ setMaxVisibleNFTs(prevMaxVisibleNFTs => prevMaxVisibleNFTs + 5);
+ if (hasNextPage) {
+ fetchNextPage();
+ }
+ }, [hasNextPage, fetchNextPage]);
+
+ useOnScreen({
+ enabled: maxVisibleNFTs < nfts?.length,
+ onIntersect: updateMaxVisibleNtfs,
+ target: listFooterRef,
+ threshold: 0.5,
+ });
+
+ const nftsByCollection = nfts.reduce(
+ (acc, nft) => {
+ const collectionKey = nft.contract || "-";
+ if (!acc[collectionKey]) {
+ acc[collectionKey] = [];
+ }
+ acc[collectionKey].push(nft);
+ return acc;
+ },
+ {} as Record,
+ );
+
+ return {
+ account,
+ hiddenNftCollections,
+ nftsByCollection,
+ listFooterRef,
+ collections,
+ maxVisibleNFTs,
+ onSend,
+ onSelectCollection,
+ };
+};
+
+export default useNftGalleryModel;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx
new file mode 100644
index 000000000000..feb7ec041fe5
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Icons.tsx
@@ -0,0 +1,73 @@
+import React from "react";
+import { Icons } from "@ledgerhq/react-ui";
+import { IconProps } from "../../types/Collection";
+
+export const mappingKeysWithIconAndName = {
+ alpha: { icon: (props: IconProps) => , name: "Alpha" },
+ black_epic: {
+ icon: (props: IconProps) => ,
+ name: "Black Epic",
+ },
+ black_legendary: {
+ icon: (props: IconProps) => ,
+ name: "Black Legendary",
+ },
+ black_mythic: {
+ icon: (props: IconProps) => ,
+ name: "Black Mythic",
+ },
+ black_rare: {
+ icon: (props: IconProps) => ,
+ name: "Black Rare",
+ },
+ black_uncommon: {
+ icon: (props: IconProps) => ,
+ name: "Black Uncommon",
+ },
+ block_9: { icon: (props: IconProps) => , name: "Block 9" },
+ block_9_450x: {
+ icon: (props: IconProps) => ,
+ name: "Block 9 450x",
+ },
+ block_78: { icon: (props: IconProps) => , name: "Block 78" },
+ block_286: {
+ icon: (props: IconProps) => ,
+ name: "Block 286",
+ },
+ block_666: {
+ icon: (props: IconProps) => ,
+ name: "Block 666",
+ },
+ common: { icon: (props: IconProps) => , name: "Common" },
+ epic: { icon: (props: IconProps) => , name: "Epic" },
+ first_tx: {
+ icon: (props: IconProps) => ,
+ name: "First Transaction",
+ },
+ hitman: { icon: (props: IconProps) => , name: "Hitman" },
+ jpeg: { icon: (props: IconProps) => , name: "JPEG" },
+ legacy: { icon: (props: IconProps) => , name: "Legacy" },
+ legendary: {
+ icon: (props: IconProps) => ,
+ name: "Legendary",
+ },
+ mythic: { icon: (props: IconProps) => , name: "Mythic" },
+ nakamoto: { icon: (props: IconProps) => , name: "Nakamoto" },
+ omega: { icon: (props: IconProps) => , name: "Omega" },
+ paliblock: {
+ icon: (props: IconProps) => ,
+ name: "PaliBlock Palindrome",
+ },
+ palindrome: {
+ icon: (props: IconProps) => ,
+ name: "Palindrome",
+ },
+ palinception: {
+ icon: (props: IconProps) => ,
+ name: "Palinception",
+ },
+ pizza: { icon: (props: IconProps) => , name: "Pizza" },
+ rare: { icon: (props: IconProps) => , name: "Rare" },
+ uncommon: { icon: (props: IconProps) => , name: "Uncommon" },
+ vintage: { icon: (props: IconProps) => , name: "Vintage" },
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx
new file mode 100644
index 000000000000..4691340a2152
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx
@@ -0,0 +1,80 @@
+import React from "react";
+import { Account } from "@ledgerhq/types-live";
+import { Box, Flex } from "@ledgerhq/react-ui";
+import { useInscriptionsModel } from "./useInscriptionsModel";
+import TableContainer from "~/renderer/components/TableContainer";
+import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
+import { OrdinalsRowProps, TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
+import TableRow from "LLD/features/Collectibles/components/Collection/TableRow";
+import ShowMore from "LLD/features/Collectibles/components/Collection/ShowMore";
+import { MediaProps } from "LLD/features/Collectibles/types/Media";
+
+type ViewProps = ReturnType;
+
+type Props = {
+ account: Account;
+};
+
+export type InscriptionsItemProps = {
+ isLoading: boolean;
+ tokenName: string;
+ collectionName: string;
+ tokenIcons: OrdinalsRowProps["tokenIcons"];
+ media: MediaProps;
+ onClick: () => void;
+};
+
+const Item: React.FC = ({
+ isLoading,
+ tokenName,
+ collectionName,
+ tokenIcons,
+ media,
+ onClick,
+}) => {
+ return (
+
+ );
+};
+
+function View({ displayedObjects, displayShowMore, onShowMore }: ViewProps) {
+ return (
+
+
+
+ {/** titlekey doesn't need to be translated so we keep it hard coded */}
+ {displayedObjects ? (
+ displayedObjects.map((item, index) => (
+
+ ))
+ ) : (
+
+ {"NOTHING TO SHOW"}
+
+ )}
+ {displayShowMore && }
+
+
+ );
+}
+
+const Inscriptions: React.FC = ({ account }: Props) => {
+ return ;
+};
+
+export default Inscriptions;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx
new file mode 100644
index 000000000000..05900b0790e9
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx
@@ -0,0 +1,32 @@
+import { useEffect, useMemo, useState } from "react";
+import { Account } from "@ledgerhq/types-live";
+import { InscriptionsItemProps } from "./index";
+import { mockedItems as InscriptionsMocked } from "LLD/features/Collectibles/__integration__/mockedInscriptions";
+type Props = {
+ account: Account;
+};
+
+export const useInscriptionsModel = ({ account }: Props) => {
+ const [displayShowMore, setDisplayShowMore] = useState(false);
+ const [displayedObjects, setDisplayedObjects] = useState([]);
+
+ const mockedItems: InscriptionsItemProps[] = useMemo(() => [...InscriptionsMocked], []);
+
+ useEffect(() => {
+ if (mockedItems.length > 3) setDisplayShowMore(true);
+ setDisplayedObjects(mockedItems.slice(0, 3));
+ }, [mockedItems]);
+
+ const onShowMore = () => {
+ setDisplayedObjects(prevDisplayedObjects => {
+ const newDisplayedObjects = [
+ ...prevDisplayedObjects,
+ ...mockedItems.slice(prevDisplayedObjects.length, prevDisplayedObjects.length + 3),
+ ];
+ if (newDisplayedObjects.length === mockedItems.length) setDisplayShowMore(false);
+ return newDisplayedObjects;
+ });
+ };
+
+ return { account, displayedObjects, displayShowMore, onShowMore };
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx
new file mode 100644
index 000000000000..6845c31536f4
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/Item.tsx
@@ -0,0 +1,43 @@
+import React from "react";
+import RowLayout from "LLD/features/Collectibles/Ordinals/components/RareSats/RowLayout";
+import IconContainer from "LLD/features/Collectibles/components/Collection/TableRow/IconContainer";
+import TokenTitle from "LLD/features/Collectibles/components/Collection/TableRow/TokenTitle";
+import { RareSat } from "LLD/features/Collectibles/types/Ordinals";
+import { Text, Flex } from "@ledgerhq/react-ui";
+
+const Item = ({
+ icons,
+ name,
+ year,
+ count,
+ utxo_size,
+ isMultipleRow,
+}: RareSat & { isMultipleRow: boolean }) => {
+ const firstColumn = (
+
+ {icons && }
+
+
+ );
+ const secondColumn = (
+
+ {year}
+
+ );
+ const thirdColumn = (
+
+ {utxo_size}
+
+ );
+
+ return (
+
+ );
+};
+
+export default Item;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx
new file mode 100644
index 000000000000..31449ce9ec39
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/RowLayout.tsx
@@ -0,0 +1,53 @@
+import React from "react";
+import { Flex } from "@ledgerhq/react-ui";
+import styled from "styled-components";
+
+type Props = {
+ firstColumnElement: JSX.Element;
+ secondColumnElement: JSX.Element;
+ thirdColumnElement?: JSX.Element;
+ bgColor?: string;
+ isMultipleRow?: boolean;
+};
+
+const Container = styled(Flex)`
+ &:first-child {
+ border-top: 1px solid ${p => p.theme.colors.palette.text.shade10};
+ padding-top: 15px;
+ }
+ &:last-child {
+ padding-bottom: 15px;
+ }
+`;
+
+const RowLayout: React.FC = ({
+ firstColumnElement,
+ secondColumnElement,
+ thirdColumnElement,
+ bgColor,
+ isMultipleRow,
+}) => {
+ const verticalPadding = isMultipleRow ? 1 : 3;
+ return (
+
+ {firstColumnElement}
+
+
+ {secondColumnElement}
+
+
+ {thirdColumnElement}
+
+
+
+ );
+};
+
+export default RowLayout;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx
new file mode 100644
index 000000000000..8ce914bf20f9
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/TableHeader.tsx
@@ -0,0 +1,27 @@
+import React from "react";
+import { Text } from "@ledgerhq/react-ui";
+import { useTranslation } from "react-i18next";
+import RowLayout from "./RowLayout";
+
+export const TableHeader = () => {
+ const { t } = useTranslation();
+
+ const Column = (translationKey: string) => (
+
+ {t(translationKey)}
+
+ );
+
+ const firstColumn = Column("ordinals.rareSats.table.type");
+ const secondColumn = Column("ordinals.rareSats.table.year");
+ const thirdColumn = Column("ordinals.rareSats.table.utxo");
+
+ return (
+
+ );
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts
new file mode 100644
index 000000000000..23e7080c2dea
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/helpers.ts
@@ -0,0 +1,107 @@
+import { mappingKeysWithIconAndName } from "../Icons";
+import { MappingKeys } from "LLD/features/Collectibles/types/Ordinals";
+import { IconProps } from "LLD/features/Collectibles/types/Collection";
+import { RareSat } from "LLD/features/Collectibles/types/Ordinals";
+import {
+ Satributes,
+ Subrange,
+ SatRange,
+ MockedRareSat,
+ Sat,
+ Icons,
+} from "LLD/features/Collectibles/types/RareSats";
+
+export const processSatType = (
+ type: string,
+ satributes: Satributes,
+ icons: Icons,
+ displayNames: string[],
+ totalCount: number,
+) => {
+ const attribute = satributes[type as MappingKeys];
+ if (attribute && attribute.count) {
+ displayNames.push(type);
+ if (mappingKeysWithIconAndName[type as MappingKeys]) {
+ icons[type] = mappingKeysWithIconAndName[type as MappingKeys].icon;
+ }
+ totalCount = attribute.count;
+ }
+ return { displayNames, totalCount };
+};
+
+export const processSatTypes = (satTypes: string[], satributes: Satributes) => {
+ let displayNames: string[] = [];
+ let totalCount = 0;
+ const icons: { [key: string]: ({ size, color, style }: IconProps) => JSX.Element } = {};
+
+ satTypes.forEach(type => {
+ const result = processSatType(type, satributes, icons, displayNames, totalCount);
+ displayNames = result.displayNames;
+ totalCount = result.totalCount;
+ });
+
+ return { displayNames, totalCount, icons };
+};
+
+export const processSubrange = (
+ subrange: Subrange,
+ satributes: Satributes,
+ year: string,
+ value: number,
+) => {
+ const { sat_types } = subrange;
+ const { displayNames, totalCount, icons } = processSatTypes(sat_types, satributes);
+
+ const name = displayNames
+ .map(dn => mappingKeysWithIconAndName[dn.toLowerCase().replace(" ", "_") as MappingKeys]?.name)
+ .filter(Boolean)
+ .join(" / ");
+
+ return {
+ count: totalCount.toString() + (totalCount === 1 ? " sat" : " sats"),
+ display_name: displayNames.join(" / "),
+ year,
+ utxo_size: value.toString(),
+ icons,
+ name,
+ };
+};
+
+export const processSatRanges = (satRanges: SatRange[], satributes: Satributes) => {
+ return satRanges.flatMap(range => {
+ const { year, value, subranges } = range;
+ return subranges.flatMap(subrange => processSubrange(subrange, satributes, year, value));
+ });
+};
+
+export const processRareSat = (sat: Sat) => {
+ const { extra_metadata } = sat;
+ const satributes = extra_metadata.utxo_details.satributes as Satributes;
+ const satRanges = extra_metadata.utxo_details.sat_ranges;
+ return processSatRanges(satRanges, satributes);
+};
+
+export const processRareSats = (rareSats: MockedRareSat[]) => {
+ return rareSats.flatMap(item => item.nfts.flatMap(processRareSat));
+};
+
+export const groupRareSats = (processedRareSats: RareSat[]) => {
+ return processedRareSats.reduce(
+ (acc, sat) => {
+ if (!acc[sat.utxo_size]) {
+ acc[sat.utxo_size] = [];
+ }
+ acc[sat.utxo_size].push(sat);
+ return acc;
+ },
+ {} as Record,
+ );
+};
+
+export const finalizeRareSats = (groupedRareSats: Record) => {
+ return Object.entries(groupedRareSats).map(([utxo_size, sats]) => ({
+ utxo_size,
+ sats,
+ isMultipleRow: sats.length > 1,
+ }));
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx
new file mode 100644
index 000000000000..838d4a0c957f
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx
@@ -0,0 +1,43 @@
+import React from "react";
+import { useRareSatsModel } from "./useRareSatsModel";
+import TableContainer from "~/renderer/components/TableContainer";
+import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
+import Item from "./Item";
+import { TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
+import { Box, Flex } from "@ledgerhq/react-ui";
+import { TableHeader as TableHeaderContainer } from "./TableHeader";
+
+type ViewProps = ReturnType;
+
+function View({ rareSats }: ViewProps) {
+ return (
+
+
+
+
+
+ {rareSats
+ ? rareSats.map(rareSatGroup => (
+
+ {rareSatGroup.sats.map(rareSat => (
+
+ ))}
+
+ ))
+ : null}
+ {/** wait for design */}
+
+
+
+ );
+}
+
+const RareSats = () => {
+ return ;
+};
+
+export default RareSats;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts
new file mode 100644
index 000000000000..931c590a56d8
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/useRareSatsModel.ts
@@ -0,0 +1,12 @@
+import { mockedRareSats } from "LLD/features/Collectibles/__integration__/mockedRareSats";
+import { processRareSats, groupRareSats, finalizeRareSats } from "./helpers";
+
+type RareSatsProps = {};
+
+export const useRareSatsModel = (_props: RareSatsProps) => {
+ const processedRareSats = processRareSats(mockedRareSats);
+ const groupedRareSats = groupRareSats(processedRareSats);
+ const finalRareSats = finalizeRareSats(groupedRareSats);
+
+ return { rareSats: finalRareSats };
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx
new file mode 100644
index 000000000000..30aed15cccc5
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx
@@ -0,0 +1,20 @@
+import React from "react";
+import { Account } from "@ledgerhq/types-live";
+import Inscriptions from "../../components/Inscriptions";
+import RareSats from "../../components/RareSats";
+import { Flex } from "@ledgerhq/react-ui";
+
+type Props = {
+ account: Account;
+};
+
+const OrdinalsAccount: React.FC = ({ account }) => {
+ return (
+
+
+
+
+ );
+};
+
+export default OrdinalsAccount;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedAccount.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedAccount.ts
new file mode 100644
index 000000000000..a58285206bfa
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedAccount.ts
@@ -0,0 +1,197 @@
+import { Account } from "@ledgerhq/types-live";
+import BigNumber from "bignumber.js";
+
+export const account: Account = {
+ type: "Account",
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:",
+ used: true,
+ seedIdentifier: "",
+ derivationMode: "",
+ index: 2,
+ freshAddress: "",
+ freshAddressPath: "",
+ blockHeight: 20372078,
+ creationDate: new Date(),
+ balance: new BigNumber(0),
+ spendableBalance: new BigNumber(0),
+ operations: [],
+ operationsCount: 0,
+ pendingOperations: [],
+ currency: {
+ type: "CryptoCurrency",
+ id: "ethereum",
+ coinType: 60,
+ name: "Ethereum",
+ managerAppName: "Ethereum",
+ ticker: "ETH",
+ scheme: "ethereum",
+ color: "#0ebdcd",
+ symbol: "Ξ",
+ family: "evm",
+ blockAvgTime: 15,
+ units: [
+ {
+ name: "ether",
+ code: "ETH",
+ magnitude: 18,
+ },
+ {
+ name: "Gwei",
+ code: "Gwei",
+ magnitude: 9,
+ },
+ {
+ name: "Mwei",
+ code: "Mwei",
+ magnitude: 6,
+ },
+ {
+ name: "Kwei",
+ code: "Kwei",
+ magnitude: 3,
+ },
+ {
+ name: "wei",
+ code: "wei",
+ magnitude: 0,
+ },
+ ],
+ ethereumLikeInfo: {
+ chainId: 1,
+ },
+ explorerViews: [
+ {
+ tx: "https://etherscan.io/tx/$hash",
+ address: "https://etherscan.io/address/$address",
+ token: "https://etherscan.io/token/$contractAddress?a=$address",
+ },
+ ],
+ keywords: ["eth", "ethereum"],
+ explorerId: "eth",
+ },
+ lastSyncDate: new Date(),
+ swapHistory: [],
+ syncHash: "",
+ balanceHistoryCache: {
+ HOUR: {
+ balances: [],
+ latestDate: 1721768400000,
+ },
+ DAY: {
+ balances: [],
+ latestDate: 1721685600000,
+ },
+ WEEK: {
+ balances: [],
+ latestDate: 1721512800000,
+ },
+ },
+ subAccounts: [],
+ nfts: [
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D+34+ethereum",
+ tokenId: "34",
+ amount: new BigNumber(1),
+ contract: "0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D+32+ethereum",
+ tokenId: "32",
+ amount: new BigNumber(1),
+ contract: "0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D+35+ethereum",
+ tokenId: "35",
+ amount: new BigNumber(1),
+ contract: "0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D+31+ethereum",
+ tokenId: "31",
+ amount: new BigNumber(1),
+ contract: "0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D+4+ethereum",
+ tokenId: "4",
+ amount: new BigNumber(1),
+ contract: "0xe3BE0054Da2F8da5002E8bdD8AA4c7fDf851E86D",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0x92E64D1a27f4F42ecAF0EF7f725f119751113A38+564+ethereum",
+ tokenId: "564",
+ amount: new BigNumber(1),
+ contract: "0x92E64D1a27f4F42ecAF0EF7f725f119751113A38",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0x19DBc1c820dd3F13260829a4E06Dda6d9EF758DB+95+ethereum",
+ tokenId: "95",
+ amount: new BigNumber(1),
+ contract: "0x19DBc1c820dd3F13260829a4E06Dda6d9EF758DB",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xfcA598e0Fcfe1ec1305b451c1d60498DB511fA70+105+ethereum",
+ tokenId: "105",
+ amount: new BigNumber(1),
+ contract: "0xfcA598e0Fcfe1ec1305b451c1d60498DB511fA70",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xe064E0b6cEca44f561752a232C4395c0d52Ed0c4+23+ethereum",
+ tokenId: "23",
+ amount: new BigNumber(1),
+ contract: "0xe064E0b6cEca44f561752a232C4395c0d52Ed0c4",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xdFDE78d2baEc499fe18f2bE74B6c287eED9511d7+33000139+ethereum",
+ tokenId: "33000139",
+ amount: new BigNumber(1),
+ contract: "0xdFDE78d2baEc499fe18f2bE74B6c287eED9511d7",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270+225000979+ethereum",
+ tokenId: "225000979",
+ amount: new BigNumber(1),
+ contract: "0xa7d8d9ef8D8Ce8992Df33D8b8CF4Aebabd5bD270",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0xf2D8eBF6BC7c4A59D72358BB4031A9ad1010b787+0+ethereum",
+ tokenId: "0",
+ amount: new BigNumber(1),
+ contract: "0xf2D8eBF6BC7c4A59D72358BB4031A9ad1010b787",
+ standard: "ERC1155",
+ currencyId: "ethereum",
+ },
+ {
+ id: "js:2:ethereum:0x823ePB4bDa11da33a7F1C907D1171e5995Fe33c7:+0x9D0f5277D19075eC1201fF94a483c5bCEe718d20+458+ethereum",
+ tokenId: "458",
+ amount: new BigNumber(1),
+ contract: "0x9D0f5277D19075eC1201fF94a483c5bCEe718d20",
+ standard: "ERC721",
+ currencyId: "ethereum",
+ },
+ ],
+};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts
new file mode 100644
index 000000000000..9d849c33eae6
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedInscriptions.ts
@@ -0,0 +1,90 @@
+import { Icons } from "@ledgerhq/react-ui";
+import { InscriptionsItemProps } from "../Ordinals/components/Inscriptions";
+
+export const mockedItems: InscriptionsItemProps[] = [
+ {
+ isLoading: false,
+ tokenName: "NodeMonke#5673",
+ collectionName: "NodeMonkes",
+ tokenIcons: [Icons.OrdinalsAlpha, Icons.OrdinalsPaliblockPalindrome],
+ media: {
+ uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png&w=1920&q=75",
+ previewUri:
+ "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252Ff976d219206858d782cccd90d25882cc77cafd3d6c159728f0d3407e25961ab0i0.png&w=1920&q=75",
+ mediaType: "image",
+ isLoading: false,
+ useFallback: true,
+ contentType: "image",
+ },
+ onClick: () => console.log("clicked"),
+ },
+ {
+ isLoading: false,
+ tokenName: "NodeMonke#5673#22",
+ collectionName: "NodeMonkes#2",
+ tokenIcons: [Icons.OrdinalsAlpha, Icons.OrdinalsPaliblockPalindrome],
+ media: {
+ uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ previewUri:
+ "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ mediaType: "image",
+ isLoading: false,
+ useFallback: true,
+ contentType: "image",
+ },
+ onClick: () => console.log("clicked"),
+ },
+ {
+ isLoading: false,
+ tokenName: "NodeMonke#5673#33",
+ collectionName: "NodeMonkes#2",
+ tokenIcons: [],
+ media: {
+ uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ previewUri:
+ "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ mediaType: "image",
+ isLoading: false,
+ useFallback: true,
+ contentType: "image",
+ },
+ onClick: () => console.log("clicked"),
+ },
+ {
+ isLoading: false,
+ tokenName: "NodeMonke#5673#44",
+ collectionName: "NodeMonkes#2",
+ tokenIcons: [Icons.OrdinalsBlackLegendary],
+ media: {
+ uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ previewUri:
+ "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ mediaType: "image",
+ isLoading: false,
+ useFallback: true,
+ contentType: "image",
+ },
+ onClick: () => console.log("clicked"),
+ },
+ {
+ isLoading: false,
+ tokenName: "NodeMonke#5673#55",
+ collectionName: "NodeMonkes#2",
+ tokenIcons: [
+ Icons.OrdinalsBlock9450X,
+ Icons.OrdinalsPaliblockPalindrome,
+ Icons.OrdinalsBlock9,
+ Icons.OrdinalsHitman,
+ ],
+ media: {
+ uri: "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ previewUri:
+ "https://www.cryptoslam.io/_next/image?url=https%3A%2F%2Fd6rvidx1ucs57.cloudfront.net%2Fcryptoslam-token-images.s3.amazonaws.com%2FBitcoin%2Fnodemonkes%2Fimage%2F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png%3Fd%3D354%26u%3Dhttps%253A%252F%252Fcryptoslam-token-images.s3.amazonaws.com%252FBitcoin%252Fnodemonkes%252Fimage%252F33199e5e35a90b516d274e8c076ca205436db00a36bc5a99d2f0e26110ca7abai0.png&w=1920&q=75",
+ mediaType: "image",
+ isLoading: false,
+ useFallback: true,
+ contentType: "image",
+ },
+ onClick: () => console.log("clicked"),
+ },
+];
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts
new file mode 100644
index 000000000000..c7413c9fae4f
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/mockedRareSats.ts
@@ -0,0 +1,1384 @@
+// Mock account from Simplehash Docs
+export const mockedRareSats = [
+ {
+ next_cursor: null,
+ next: null,
+ previous: null,
+ nfts: [
+ {
+ nft_id: "utxo.7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb.1",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "1",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-14T11:34:34",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-14T11:34:34",
+ last_acquired_date: "2024-03-14T11:34:34",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: null,
+ name: null,
+ description: null,
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: null,
+ distinct_nft_count: null,
+ total_quantity: null,
+ chains: [],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-14T11:34:34",
+ block_number: 834655,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 0,
+ satributes: {
+ common: {
+ count: 8000,
+ display_name: "Common",
+ description: "Any sat that is not the first sat of its block",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 574534229491726,
+ value: 8000,
+ distinct_rare_sats: 0,
+ year: "2011",
+ subranges: [
+ {
+ starting_sat: 574534229491726,
+ value: 8000,
+ sat_types: ["common"],
+ },
+ ],
+ },
+ ],
+ block_number: 834655,
+ value: 8000,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.7893390614d9a5608e39ea637e5794f7564d3fcdd5ad46105f349c2cf45272fb.0",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "0",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-14T11:34:34",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-14T11:34:34",
+ last_acquired_date: "2024-03-14T11:34:34",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: null,
+ name: null,
+ description: null,
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: null,
+ distinct_nft_count: null,
+ total_quantity: null,
+ chains: [],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-14T11:34:34",
+ block_number: 834655,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 0,
+ satributes: {
+ common: {
+ count: 9000,
+ display_name: "Common",
+ description: "Any sat that is not the first sat of its block",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 574534229482726,
+ value: 9000,
+ distinct_rare_sats: 0,
+ year: "2011",
+ subranges: [
+ {
+ starting_sat: 574534229482726,
+ value: 9000,
+ sat_types: ["common"],
+ },
+ ],
+ },
+ ],
+ block_number: 834655,
+ value: 9000,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.51fb634f0fefa3441e1a60090d9e292ce1f0803258c2dae818410db4192c89f6.0",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "0",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T10:37:28",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T10:37:28",
+ last_acquired_date: "2024-03-08T10:37:28",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: null,
+ name: null,
+ description: null,
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: null,
+ distinct_nft_count: null,
+ total_quantity: null,
+ chains: [],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T10:37:28",
+ block_number: 833719,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 0,
+ satributes: {
+ common: {
+ count: 600,
+ display_name: "Common",
+ description: "Any sat that is not the first sat of its block",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 1032093336971063,
+ value: 600,
+ distinct_rare_sats: 0,
+ year: "2012",
+ subranges: [
+ {
+ starting_sat: 1032093336971063,
+ value: 600,
+ sat_types: ["common"],
+ },
+ ],
+ },
+ ],
+ block_number: 833719,
+ value: 600,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "witness_v1_taproot",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.b2011509f56ca83378d5e72e413ed5c939cfa4ff3d82680c1b12b5a6b406ac95.0",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "0",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T10:33:01",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T10:33:01",
+ last_acquired_date: "2024-03-08T10:33:01",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: null,
+ name: null,
+ description: null,
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: null,
+ distinct_nft_count: null,
+ total_quantity: null,
+ chains: [],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T10:33:01",
+ block_number: 833718,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 0,
+ satributes: {
+ common: {
+ count: 600,
+ display_name: "Common",
+ description: "Any sat that is not the first sat of its block",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 1032093336949888,
+ value: 600,
+ distinct_rare_sats: 0,
+ year: "2012",
+ subranges: [
+ {
+ starting_sat: 1032093336949888,
+ value: 600,
+ sat_types: ["common"],
+ },
+ ],
+ },
+ ],
+ block_number: 833718,
+ value: 600,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.398901189471c069dd74068a2884e02829c831432e705b28a0c337696e681b97.0",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "0",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T10:06:46",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T10:06:46",
+ last_acquired_date: "2024-03-08T10:06:46",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: null,
+ name: null,
+ description: null,
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: null,
+ distinct_nft_count: null,
+ total_quantity: null,
+ chains: [],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T10:06:46",
+ block_number: 833714,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 0,
+ satributes: {
+ common: {
+ count: 600,
+ display_name: "Common",
+ description: "Any sat that is not the first sat of its block",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_common.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 1032093336943299,
+ value: 600,
+ distinct_rare_sats: 0,
+ year: "2012",
+ subranges: [
+ {
+ starting_sat: 1032093336943299,
+ value: 600,
+ sat_types: ["common"],
+ },
+ ],
+ },
+ ],
+ block_number: 833714,
+ value: 600,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.5",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "5",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T09:47:36",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T09:47:36",
+ last_acquired_date: "2024-03-08T09:47:36",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: "0123456789abcdeffedcba9876543210",
+ name: "Rare Sats",
+ description:
+ 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.',
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: 5284108,
+ distinct_nft_count: 7259220,
+ total_quantity: 7259196,
+ chains: ["utxo"],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T09:47:36",
+ block_number: 833711,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 330,
+ satributes: {
+ block_78: {
+ count: 330,
+ display_name: "Block 78",
+ description:
+ "Sats mined by Hal Finney in block 78 which was the first block mined by someone other than Satoshi",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_block78.png",
+ },
+ vintage: {
+ count: 330,
+ display_name: "Vintage",
+ description: "Sats mined in the first 1,000 blocks",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_vintage.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 392582274563,
+ value: 330,
+ distinct_rare_sats: 330,
+ year: "2009",
+ subranges: [
+ {
+ starting_sat: 392582274563,
+ value: 330,
+ sat_types: ["block_78", "vintage"],
+ },
+ ],
+ },
+ ],
+ block_number: 833711,
+ value: 330,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.4",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "4",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T09:47:36",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T09:47:36",
+ last_acquired_date: "2024-03-08T09:47:36",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: "0123456789abcdeffedcba9876543210",
+ name: "Rare Sats",
+ description:
+ 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.',
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: 5284108,
+ distinct_nft_count: 7259220,
+ total_quantity: 7259196,
+ chains: ["utxo"],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T09:47:36",
+ block_number: 833711,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 330,
+ satributes: {
+ vintage: {
+ count: 330,
+ display_name: "Vintage",
+ description: "Sats mined in the first 1,000 blocks",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_vintage.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 4834087454144,
+ value: 330,
+ distinct_rare_sats: 330,
+ year: "2009",
+ subranges: [
+ {
+ starting_sat: 4834087454144,
+ value: 330,
+ sat_types: ["vintage"],
+ },
+ ],
+ },
+ ],
+ block_number: 833711,
+ value: 330,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.3",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "3",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T09:47:36",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T09:47:36",
+ last_acquired_date: "2024-03-08T09:47:36",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: "0123456789abcdeffedcba9876543210",
+ name: "Rare Sats",
+ description:
+ 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.',
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: 5284108,
+ distinct_nft_count: 7259220,
+ total_quantity: 7259196,
+ chains: ["utxo"],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T09:47:36",
+ block_number: 833711,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 330,
+ satributes: {
+ pizza: {
+ count: 330,
+ display_name: "Pizza",
+ description:
+ "Sat from the 10,000 Bitcoins used to purchase two Papa John's pizzas on May 22, 2010",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_pizza.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 265675444186667,
+ value: 330,
+ distinct_rare_sats: 330,
+ year: "2010",
+ subranges: [
+ {
+ starting_sat: 265675444186667,
+ value: 330,
+ sat_types: ["pizza"],
+ },
+ ],
+ },
+ ],
+ block_number: 833711,
+ value: 330,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.2",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "2",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T09:47:36",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T09:47:36",
+ last_acquired_date: "2024-03-08T09:47:36",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: "0123456789abcdeffedcba9876543210",
+ name: "Rare Sats",
+ description:
+ 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.',
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: 5284108,
+ distinct_nft_count: 7259220,
+ total_quantity: 7259196,
+ chains: ["utxo"],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T09:47:36",
+ block_number: 833711,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 547,
+ satributes: {
+ jpeg: {
+ count: 547,
+ display_name: "JPEG",
+ description:
+ "Sats involved in the possible first bitcoin trade for an image on February 24, 2010",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_jpeg.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 152060443363905,
+ value: 547,
+ distinct_rare_sats: 547,
+ year: "2009",
+ subranges: [
+ {
+ starting_sat: 152060443363905,
+ value: 547,
+ sat_types: ["jpeg"],
+ },
+ ],
+ },
+ ],
+ block_number: 833711,
+ value: 547,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ {
+ nft_id: "utxo.68f11cb8770c6e761a5763bb47f00b368e03a4960046f441617c46edad2b0215.1",
+ chain: "utxo",
+ contract_address: "",
+ token_id: "1",
+ name: null,
+ description: null,
+ previews: {
+ image_small_url: null,
+ image_medium_url: null,
+ image_large_url: null,
+ image_opengraph_url: null,
+ blurhash: null,
+ predominant_color: null,
+ },
+ image_url: null,
+ image_properties: null,
+ video_url: null,
+ video_properties: null,
+ audio_url: null,
+ audio_properties: null,
+ model_url: null,
+ model_properties: null,
+ other_url: null,
+ other_properties: null,
+ background_color: null,
+ external_url: null,
+ created_date: "2024-03-08T09:47:36",
+ status: "minted",
+ token_count: 1,
+ owner_count: 1,
+ owners: [
+ {
+ owner_address: "",
+ quantity: 1,
+ quantity_string: "1",
+ first_acquired_date: "2024-03-08T09:47:36",
+ last_acquired_date: "2024-03-08T09:47:36",
+ },
+ ],
+ contract: {
+ type: "UTXO",
+ name: null,
+ symbol: null,
+ deployed_by: null,
+ deployed_via_contract: null,
+ owned_by: null,
+ has_multiple_collections: false,
+ },
+ collection: {
+ collection_id: "0123456789abcdeffedcba9876543210",
+ name: "Rare Sats",
+ description:
+ 'Rare Sats are attributes, or "satributes," ascribed to different types of sats. Sats are the smallest unit of a Bitcoin, and satributes commemorate special moments like when a sat was mined or used in a transaction.',
+ image_url: null,
+ image_properties: null,
+ banner_image_url: null,
+ category: null,
+ is_nsfw: null,
+ external_url: null,
+ twitter_username: null,
+ discord_url: null,
+ instagram_username: null,
+ medium_username: null,
+ telegram_url: null,
+ marketplace_pages: [],
+ metaplex_mint: null,
+ metaplex_candy_machine: null,
+ metaplex_first_verified_creator: null,
+ spam_score: null,
+ floor_prices: [],
+ top_bids: [],
+ distinct_owner_count: 5284108,
+ distinct_nft_count: 7259220,
+ total_quantity: 7259196,
+ chains: ["utxo"],
+ top_contracts: [],
+ collection_royalties: [],
+ },
+ last_sale: null,
+ first_created: {
+ minted_to: "",
+ quantity: 1,
+ quantity_string: "1",
+ timestamp: "2024-03-08T09:47:36",
+ block_number: 833711,
+ transaction: "",
+ transaction_initiator: null,
+ },
+ rarity: {
+ rank: null,
+ score: null,
+ unique_attributes: null,
+ },
+ royalty: [],
+ extra_metadata: {
+ attributes: [],
+ utxo_details: {
+ distinct_rare_sats: 555,
+ satributes: {
+ nakamoto: {
+ count: 555,
+ display_name: "Nakamoto",
+ description: "Sat mined by Satoshi Nakamoto",
+ icon: "https://cdn.simplehash.com/rare_sats/satribute_nakamoto.png",
+ },
+ },
+ sat_ranges: [
+ {
+ starting_sat: 95469010861290,
+ value: 555,
+ distinct_rare_sats: 555,
+ year: "2009",
+ subranges: [
+ {
+ starting_sat: 95469010861290,
+ value: 555,
+ sat_types: ["nakamoto"],
+ },
+ ],
+ },
+ ],
+ block_number: 833711,
+ value: 555,
+ script_pub_key: {
+ asm: "",
+ desc: "",
+ hex: "",
+ address: "",
+ type: "",
+ },
+ },
+ image_original_url: null,
+ animation_original_url: null,
+ metadata_original_url: null,
+ },
+ },
+ ],
+ },
+];
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/nftsCollection.test.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/nftsCollection.test.tsx
index d2202da4de32..5104ff9891f1 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/nftsCollection.test.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/nftsCollection.test.tsx
@@ -2,73 +2,80 @@
* @jest-environment jsdom
*/
import React from "react";
-import { render, screen } from "tests/testUtils";
-import { account, NftCollectionTest, NoNftCollectionTest } from "./shared";
+import { render, screen, waitFor } from "tests/testUtils";
+import { NftCollectionTest, NoNftCollectionTest } from "./shared";
+import { account } from "./mockedAccount";
+
+jest.mock(
+ "electron",
+ () => ({ ipcRenderer: { on: jest.fn(), send: jest.fn(), invoke: jest.fn() } }),
+ { virtual: true },
+);
describe("displayNftCollection", () => {
- it("should display NFTs collection", async () => {
+ it("should display NFTs collections", async () => {
render(, {
initialState: {
accounts: [account],
- overriddenFeatureFlagsSelector: {
- nftsFromSimplehash: false,
- },
},
initialRoute: `/`,
});
- await expect(screen.getByText(/0x670fd103b1a08628e9557cd66b87ded841115190/i)).toBeVisible();
+ await waitFor(() => expect(screen.getByText(/momentum/i)).toBeVisible());
await expect(screen.getByText(/receive nft/i)).toBeVisible();
await expect(screen.getByText(/see gallery/i)).toBeVisible();
+ await expect(screen.getByText(/see more collections/i)).toBeVisible();
});
it("should open the NFTs gallery", async () => {
const { user } = render(, {
initialState: {
accounts: [account],
- overriddenFeatureFlagsSelector: {
- nftsFromSimplehash: false,
- },
},
initialRoute: `/`,
});
- await expect(screen.getByText(/0x670fd103b1a08628e9557cd66b87ded841115190/i)).toBeVisible();
+ await waitFor(() => expect(screen.getByText(/momentum/i)).toBeVisible());
await expect(screen.getByText(/receive nft/i)).toBeVisible();
await expect(screen.getByText(/see gallery/i)).toBeVisible();
await user.click(screen.getByText(/see gallery/i));
await expect(screen.getByText(/all nft/i)).toBeVisible();
- // Check breadcrumb and page title
- await expect(screen.getAllByText(/nft/i).length).toBe(2);
});
- it("should open the corresponding NFTs collection and it should open detail drawer", async () => {
+ it("should open the corresponding NFTs collection and the correct detail drawer", async () => {
const { user } = render(, {
initialState: {
accounts: [account],
- overriddenFeatureFlagsSelector: {
- nftsFromSimplehash: false,
- },
},
initialRoute: `/`,
});
- await expect(screen.getByText(/0x670fd103b1a08628e9557cd66b87ded841115190/i)).toBeVisible();
- await expect(screen.getByText(/receive nft/i)).toBeVisible();
- await expect(screen.getByText(/see gallery/i)).toBeVisible();
- await user.click(screen.getByText(/0x670fd103b1a08628e9557cd66b87ded841115190/i));
- await expect(screen.getByText(/all nft/i)).toBeVisible();
- // Check breadcrumb and page title
- await expect(screen.getAllByText(/0x670fd103b1a08628e9557cd66b87ded841115190/i).length).toBe(2);
+ // Check initial state
+ await waitFor(() => expect(screen.getByText(/momentum/i)).toBeVisible());
+
+ // Open specific collection
+ await user.click(screen.getByText(/momentum/i));
+ await waitFor(() => expect(screen.getByText(/ID: 35/i)).toBeVisible());
+
+ // Open Detail drawer
+ await user.click(screen.getByText(/ID: 35/i));
+ await screen.findByTestId("side-drawer-container");
+ await screen.findByTestId("drawer-close-button");
+ await screen.findByText(/properties/i);
+
+ // Open external viewer
+ await user.click(screen.getByTestId("external-viewer-button"));
+ await expect(screen.getByText(/open in opensea.io/i)).toBeVisible();
+
+ // Close drawer
+ await waitFor(() => user.click(screen.getByTestId("drawer-close-button")));
+ await waitFor(() => expect(screen.queryByTestId("side-drawer-container")).toBeNull());
});
it("should not display nft", async () => {
render(, {
initialState: {
accounts: [account],
- overriddenFeatureFlagsSelector: {
- nftsFromSimplehash: false,
- },
},
initialRoute: `/`,
});
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/shared.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/shared.tsx
index dffdf0d34556..e7faeee601a7 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/shared.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/shared.tsx
@@ -1,24 +1,23 @@
import { genAccount } from "@ledgerhq/coin-framework/lib/mocks/account";
import React from "react";
import { Switch, Route, withRouter } from "react-router";
-import NftCollection from "../Nfts/Collection";
-import NFTGallery from "~/renderer/screens/nft/Gallery";
import NftBreadCrumb from "LLD/components/BreadCrumb";
-
-export const account = genAccount("ethereum1", {
- withNft: true,
- operationsSize: 30,
-});
+import NFTGallery from "../Nfts/screens/Gallery";
+import NftCollection from "../Nfts/screens/Collection";
+import NftCollections from "../Nfts/Collections";
+import { account } from "./mockedAccount";
const NftCollectionNavigation = () => (
- } />
+ } />
+ } />
} />
);
const NftCollectionTestBase = () => (
<>
+
>
@@ -27,7 +26,8 @@ const NftCollectionTestBase = () => (
export const NftCollectionTest = withRouter(NftCollectionTestBase);
export const NoNftCollectionTest = withRouter(() => (
<>
+
-
+
>
));
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/EmptyCollection.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/EmptyCollection.tsx
index 64bcd621f23d..464912b45c42 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/EmptyCollection.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/EmptyCollection.tsx
@@ -1,7 +1,8 @@
import React, { ReactNode } from "react";
import styled from "styled-components";
import { useTranslation } from "react-i18next";
-import { CollectibleTypeEnum, CollectibleType } from "LLD/features/Collectibles/types/Collectibles";
+import { CollectibleType } from "LLD/features/Collectibles/types/Collectibles";
+import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collectibles";
import Text from "~/renderer/components/Text";
import LabelWithExternalIcon from "~/renderer/components/LabelWithExternalIcon";
import { supportLinkByTokenType } from "~/config/urls";
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableHeader.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableHeader.tsx
index cde9e9547356..9892c5ead189 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableHeader.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableHeader.tsx
@@ -2,7 +2,7 @@ import { Flex } from "@ledgerhq/react-ui";
import React from "react";
import { useTranslation } from "react-i18next";
import { TableHeader as HeaderContainer } from "~/renderer/components/TableContainer";
-import { TableHeaderProps as Props } from "../../types/Collection";
+import { TableHeaderProps as Props } from "LLD/features/Collectibles/types/Collection";
const TableHeader: React.FC = ({ titleKey, actions }) => {
const { t } = useTranslation();
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx
new file mode 100644
index 000000000000..79bd9ee94c49
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/IconContainer.tsx
@@ -0,0 +1,29 @@
+import React from "react";
+import { Flex } from "@ledgerhq/react-ui";
+import { IconProps } from "LLD/features/Collectibles/types/Collection";
+
+type Props = {
+ icons: (({ size, color, style }: IconProps) => JSX.Element)[];
+};
+
+const IconContainer: React.FC = ({ icons }) => {
+ return (
+
+ {icons.map((Icon, index) => (
+
+ ))}
+
+ );
+};
+
+export default IconContainer;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx
index d41eed6c96c3..c5d11986eaf9 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/TokenTitle.tsx
@@ -1,18 +1,39 @@
import React from "react";
import { Skeleton } from "../../Skeleton";
-import { Text } from "@ledgerhq/react-ui";
+import { Flex, Text } from "@ledgerhq/react-ui";
type Props = {
tokenName: string | string[];
isLoading: boolean;
+ collectionName?: string;
+ complementaryData?: string;
};
-const TokenTitle: React.FC = ({ tokenName, isLoading }) => {
+const TokenTitle: React.FC = ({
+ tokenName,
+ isLoading,
+ collectionName,
+ complementaryData,
+}) => {
+ const isInsideRareSatRow = Boolean(complementaryData);
return (
-
- {tokenName}
-
+
+
+ {tokenName}
+
+
+ {collectionName || complementaryData}
+
+
);
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx
index c51d8e2eab55..6c0ef4bf55d2 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/Collection/TableRow/index.tsx
@@ -10,6 +10,7 @@ import {
} from "LLD/features/Collectibles/utils/typeGuardsChecker";
import { RowProps as Props } from "LLD/features/Collectibles/types/Collection";
import TokenTitle from "./TokenTitle";
+import IconContainer from "./IconContainer";
const Container = styled(Box)`
&.disabled {
@@ -37,14 +38,18 @@ const TableRow: React.FC = props => {
const nftCount = () => {
return (
-
+ <>
{isNFTRow(props) && (
-
- {props.numberOfNfts || 0}
-
+
+
+ {props.numberOfNfts || 0}
+
+
+ )}
+ {isOrdinalsRow(props) && props.tokenIcons.length != 0 && (
+
)}
- {isOrdinalsRow(props) && null}
-
+ >
);
};
@@ -59,7 +64,11 @@ const TableRow: React.FC = props => {
>
{mediaBox()}
-
+
{nftCount()}
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/CollectionName.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/CollectionName.tsx
index 7da030f526a4..188f2ac4627a 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/CollectionName.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/CollectionName.tsx
@@ -4,8 +4,9 @@ import { Account, ProtoNFT } from "@ledgerhq/types-live";
import NFTCollectionContextMenu from "~/renderer/components/ContextMenu/NFTCollectionContextMenu";
import { Skeleton } from "LLD/features/Collectibles/components";
import styled from "styled-components";
-import { IconsLegacy } from "@ledgerhq/react-ui";
-import { FieldStatus } from "LLD/features/Collectibles/types/DetailDrawer";
+import { Flex, IconsLegacy } from "@ledgerhq/react-ui";
+import { FieldStatus } from "LLD/features/Collectibles/types/enum/DetailDrawer";
+import { Text } from "@ledgerhq/react-ui";
const Dots = styled.div`
justify-content: flex-end;
@@ -18,19 +19,22 @@ const Dots = styled.div`
color: ${p => p.theme.colors.palette.text.shade80};
}
`;
-const Container = styled.div`
- display: flex;
- column-gap: 10px;
-`;
type Props = {
nft?: ProtoNFT;
fallback?: string;
account?: Account;
showHideMenu?: boolean;
-}; // TODO Make me pretty
+ collectiblesNumber?: number;
+};
-const CollectionNameComponent: React.FC = ({ nft, fallback, account, showHideMenu }) => {
+const CollectionNameComponent: React.FC = ({
+ nft,
+ fallback,
+ account,
+ showHideMenu,
+ collectiblesNumber,
+}) => {
const { status, metadata } = useNftCollectionMetadata(nft?.contract, nft?.currencyId);
const { tokenName } = metadata || {};
const loading = status === FieldStatus.Loading;
@@ -38,8 +42,13 @@ const CollectionNameComponent: React.FC = ({ nft, fallback, account, show
return (
-
+
{tokenName || fallback || "-"}
+ {collectiblesNumber && (
+
+ ({collectiblesNumber})
+
+ )}
{isComponentReady && (
= ({ nft, fallback, account, show
)}
-
+
);
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/CopyableField.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/CopyableField.tsx
index b30bff336e4c..b6decd673b3c 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/CopyableField.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/CopyableField.tsx
@@ -8,6 +8,7 @@ const CopyableFieldContainer = styled.div`
display: inline-flex;
position: relative;
max-width: 100%;
+ min-width: 4.5rem;
${GradientHover} {
display: none;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/DetailField.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/DetailField.tsx
index d0cd6c6788dc..29de511adc54 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/DetailField.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/DetailField.tsx
@@ -32,7 +32,7 @@ const Pre = styled.span`
white-space: pre-line;
display: block;
unicode-bidi: embed;
- line-break: anywhere;
+ word-break: break-word;
line-height: 15px;
`;
diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/ExternalViewerButton.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/ExternalViewerButton.tsx
index 609829d0f7d9..c391c72d7392 100644
--- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/ExternalViewerButton.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/components/DetailDrawer/components/ExternalViewerButton.tsx
@@ -1,7 +1,8 @@
import React, { useCallback, memo, ReactElement } from "react";
import styled from "styled-components";
import { useHistory } from "react-router-dom";
-import { ExternalViewerButtonProps, ItemType } from "LLD/features/Collectibles/types/DetailDrawer";
+import { ExternalViewerButtonProps } from "LLD/features/Collectibles/types/DetailDrawer";
+import { ItemType } from "LLD/features/Collectibles/types/enum/DetailDrawer";
import Box from "~/renderer/components/Box";
import Button from "~/renderer/components/Button";
import DropDownSelector, { DropDownItem } from "~/renderer/components/DropDownSelector";
@@ -76,6 +77,7 @@ const ExternalViewerButtonComponent: React.FC = ({
{() => (
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Error.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Error.tsx
index d103d421273a..80939f245e6b 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Error.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Error.tsx
@@ -1,13 +1,19 @@
-import { Box, Flex, Icons, Text } from "@ledgerhq/react-ui";
+import { Box, Flex, Icons, Link, Text } from "@ledgerhq/react-ui";
import React from "react";
import styled, { useTheme } from "styled-components";
import ButtonV3 from "~/renderer/components/ButtonV3";
+import { AnalyticsPage } from "../hooks/useLedgerSyncAnalytics";
+import TrackPage from "~/renderer/analytics/TrackPage";
+import { useTranslation } from "react-i18next";
type Props = {
title?: string;
description?: string;
cta?: string;
onClick?: () => void;
+ analyticsPage?: AnalyticsPage;
+ ctaVariant?: "shade" | "main";
+ onClose?: () => void;
};
const Container = styled(Box)`
@@ -20,10 +26,20 @@ const Container = styled(Box)`
justify-content: center;
`;
-export const Error = ({ title, description, cta, onClick }: Props) => {
+export const Error = ({
+ title,
+ description,
+ cta,
+ onClick,
+ analyticsPage,
+ ctaVariant = "shade",
+ onClose,
+}: Props) => {
const { colors } = useTheme();
+ const { t } = useTranslation();
return (
+
@@ -34,10 +50,18 @@ export const Error = ({ title, description, cta, onClick }: Props) => {
{description}
{cta && onClick && (
-
+
{cta}
)}
+
+ {onClose && (
+
+
+ {t("walletSync.close")}
+
+
+ )}
);
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/GenericStatusDisplay.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/GenericStatusDisplay.tsx
new file mode 100644
index 000000000000..0962b3f659b5
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/GenericStatusDisplay.tsx
@@ -0,0 +1,87 @@
+import { Box, Flex, Icons, Text } from "@ledgerhq/react-ui";
+import React from "react";
+import { useTranslation } from "react-i18next";
+import styled, { useTheme } from "styled-components";
+import { AnalyticsFlow, AnalyticsPage } from "../hooks/useLedgerSyncAnalytics";
+import TrackPage from "~/renderer/analytics/TrackPage";
+import ButtonV3 from "~/renderer/components/ButtonV3";
+
+export type GenericProps = {
+ title?: string;
+ description?: string;
+ withClose?: boolean;
+ withCta?: boolean;
+ onClick?: () => void;
+ onClose?: () => void;
+ analyticsPage?: AnalyticsPage;
+ type?: "success" | "info";
+ specificCta?: string;
+};
+
+const Container = styled(Box)`
+ background-color: ${p => p.theme.colors.opacityDefault.c05};
+ border-radius: 100%;
+ height: 72px;
+ width: 72px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+`;
+
+export const GenericStatusDisplay = ({
+ title,
+ description,
+ withClose = false,
+ withCta = false,
+ onClick,
+ onClose,
+ analyticsPage,
+ type,
+ specificCta,
+}: GenericProps) => {
+ const { t } = useTranslation();
+ const { colors } = useTheme();
+
+ return (
+
+
+
+ {type === "info" ? (
+
+ ) : (
+
+ )}
+
+
+ {title}
+
+
+ {description}
+
+
+ {withClose || withCta ? (
+
+ {withCta && onClick && (
+
+ {specificCta ?? t("walletSync.success.synchAnother")}
+
+ )}
+ {withClose && (
+
+ {t("walletSync.success.close")}
+
+ )}
+
+ ) : null}
+
+ );
+};
+
+const BottomContainer = styled(Flex)``;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Info.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Info.tsx
new file mode 100644
index 000000000000..b0217cf9179b
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Info.tsx
@@ -0,0 +1,4 @@
+import React from "react";
+import { GenericProps, GenericStatusDisplay } from "./GenericStatusDisplay";
+
+export const Info = (props: GenericProps) => ;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Success.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Success.tsx
index f409e01401c8..288fc1b2beac 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Success.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/components/Success.tsx
@@ -1,79 +1,4 @@
-import { Box, Flex, Icons, Text } from "@ledgerhq/react-ui";
import React from "react";
-import { useTranslation } from "react-i18next";
-import styled, { useTheme } from "styled-components";
-import TrackPage from "~/renderer/analytics/TrackPage";
-import ButtonV3 from "~/renderer/components/ButtonV3";
-import { AnalyticsPage } from "../hooks/useWalletSyncAnalytics";
+import { GenericProps, GenericStatusDisplay } from "./GenericStatusDisplay";
-type Props = {
- title?: string;
- description?: string;
- withClose?: boolean;
- withCta?: boolean;
- onClick?: () => void;
- onClose?: () => void;
- analyticsPage?: AnalyticsPage;
-};
-
-const Container = styled(Box)`
- background-color: ${p => p.theme.colors.opacityDefault.c05};
- border-radius: 100%;
- height: 72px;
- width: 72px;
- display: flex;
- align-items: center;
- justify-content: center;
-`;
-
-export const Success = ({
- title,
- description,
- withClose = false,
- withCta = false,
- onClick,
- onClose,
- analyticsPage,
-}: Props) => {
- const { t } = useTranslation();
- const { colors } = useTheme();
-
- return (
-
-
-
-
-
-
- {title}
-
-
- {description}
-
-
- {withClose || withCta ? (
-
- {withCta && onClick && (
-
- {t("walletSync.success.synchAnother")}
-
- )}
- {withClose && (
-
- {t("walletSync.success.close")}
-
- )}
-
- ) : null}
-
- );
-};
-
-const BottomContainer = styled(Flex)``;
+export const Success = (props: GenericProps) => ;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useAddMember.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useAddMember.ts
index 889a1d1da5ad..2bff58d10c50 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useAddMember.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useAddMember.ts
@@ -1,25 +1,31 @@
-import { memberCredentialsSelector, setTrustchain } from "@ledgerhq/trustchain/store";
+import {
+ memberCredentialsSelector,
+ setTrustchain,
+ trustchainSelector,
+} from "@ledgerhq/trustchain/store";
import { useDispatch, useSelector } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
-import {
- MemberCredentials,
- TrustchainResult,
- TrustchainResultType,
-} from "@ledgerhq/trustchain/types";
+import { useTrustchainSdk } from "./useTrustchainSdk";
+import { TrustchainResult, TrustchainResultType } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useRef, useState } from "react";
+import {
+ TrustchainAlreadyInitialized,
+ TrustchainAlreadyInitializedWithOtherSeed,
+} from "@ledgerhq/trustchain/errors";
export function useAddMember({ device }: { device: Device | null }) {
const dispatch = useDispatch();
const sdk = useTrustchainSdk();
const memberCredentials = useSelector(memberCredentialsSelector);
+ const trustchain = useSelector(trustchainSelector);
const [error, setError] = useState(null);
const [userDeviceInteraction, setUserDeviceInteraction] = useState(false);
const sdkRef = useRef(sdk);
const deviceRef = useRef(device);
+ const trustchainRef = useRef(trustchain);
const memberCredentialsRef = useRef(memberCredentials);
const transitionToNextScreen = useCallback(
@@ -28,10 +34,12 @@ export function useAddMember({ device }: { device: Device | null }) {
dispatch(
setFlow({
flow: Flow.Activation,
- step:
+ step: Step.ActivationLoading,
+ nextStep:
trustchainResult.type === TrustchainResultType.created
? Step.ActivationFinal
: Step.SynchronizationFinal,
+ hasTrustchainBeenCreated: trustchainResult.type === TrustchainResultType.created,
}),
);
},
@@ -52,26 +60,34 @@ export function useAddMember({ device }: { device: Device | null }) {
};
useEffect(() => {
- if (!deviceRef.current) {
- handleMissingDevice();
- }
-
const addMember = async () => {
try {
- await runWithDevice(deviceRef.current?.deviceId, async transport => {
- const trustchainResult = await sdkRef.current.getOrCreateTrustchain(
- transport,
- memberCredentialsRef.current as MemberCredentials,
- {
- onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
- onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
- },
- );
+ if (!deviceRef.current) {
+ return handleMissingDevice();
+ }
+ if (!memberCredentialsRef.current) {
+ throw new Error("memberCredentials is not set");
+ }
+ const trustchainResult = await sdkRef.current.getOrCreateTrustchain(
+ deviceRef.current.deviceId,
+ memberCredentialsRef.current,
+ {
+ onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
+ onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
+ },
+ undefined,
+ trustchainRef?.current?.rootId,
+ );
- transitionToNextScreen(trustchainResult);
- });
+ transitionToNextScreen(trustchainResult);
} catch (error) {
- setError(error as Error);
+ if (error instanceof TrustchainAlreadyInitialized) {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.AlreadySecuredSameSeed }));
+ } else if (error instanceof TrustchainAlreadyInitializedWithOtherSeed) {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.AlreadySecuredOtherSeed }));
+ } else {
+ setError(error as Error);
+ }
}
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useFlows.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useFlows.ts
index 73ce02466ae9..187b41c72902 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useFlows.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useFlows.ts
@@ -1,3 +1,4 @@
+import { trustchainSelector } from "@ledgerhq/trustchain/store";
import { useDispatch, useSelector } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import {
@@ -22,9 +23,10 @@ export const FlowOptions: Record<
1: Step.CreateOrSynchronize,
2: Step.DeviceAction,
3: Step.CreateOrSynchronizeTrustChain,
- 4: Step.ActivationFinal,
- 5: Step.SynchronizationFinal,
- 6: Step.SynchronizationError,
+ 4: Step.ActivationLoading,
+ 5: Step.ActivationFinal,
+ 6: Step.SynchronizationFinal,
+ 7: Step.SynchronizationError,
},
},
[Flow.Synchronize]: {
@@ -32,7 +34,8 @@ export const FlowOptions: Record<
1: Step.SynchronizeMode,
2: Step.SynchronizeWithQRCode,
3: Step.PinCode,
- 4: Step.Synchronized,
+ 4: Step.SynchronizeLoading,
+ 5: Step.Synchronized,
},
},
[Flow.ManageBackup]: {
@@ -53,9 +56,9 @@ export const FlowOptions: Record<
7: Step.AutoRemoveInstance,
},
},
- [Flow.WalletSyncActivated]: {
+ [Flow.LedgerSyncActivated]: {
steps: {
- 1: Step.WalletSyncActivated,
+ 1: Step.LedgerSyncActivated,
},
},
};
@@ -70,11 +73,13 @@ export const STEPS_WITH_BACK: Step[] = [
Step.ManageBackup,
Step.DeleteBackup,
Step.SynchronizedInstances,
+ Step.SynchronizeMode,
+ Step.SynchronizeWithQRCode,
];
export const useFlows = () => {
const dispatch = useDispatch();
-
+ const trustchain = useSelector(trustchainSelector);
const currentFlow = useSelector(walletSyncFlowSelector);
const currentStep = useSelector(walletSyncStepSelector);
@@ -94,9 +99,9 @@ export const useFlows = () => {
dispatch(setFlow({ flow: currentFlow, step: stepsRecord[newStep] }));
};
- const goToWelcomeScreenWalletSync = (isWalletSyncActivated: boolean) => {
- if (isWalletSyncActivated) {
- dispatch(setFlow({ flow: Flow.WalletSyncActivated, step: Step.WalletSyncActivated }));
+ const goToWelcomeScreenWalletSync = () => {
+ if (trustchain?.rootId) {
+ dispatch(setFlow({ flow: Flow.LedgerSyncActivated, step: Step.LedgerSyncActivated }));
} else {
dispatch(setFlow({ flow: Flow.Activation, step: Step.CreateOrSynchronize }));
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useGetMembers.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useGetMembers.ts
index 6d48b83adb4e..f87b2d9e14fb 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useGetMembers.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useGetMembers.ts
@@ -5,16 +5,20 @@ import { QueryKey } from "./type.hooks";
import { useQuery } from "@tanstack/react-query";
import { useEffect } from "react";
import { useLifeCycle } from "./walletSync.hooks";
+import { TrustchainNotFound } from "@ledgerhq/trustchain/errors";
export function useGetMembers() {
const sdk = useTrustchainSdk();
const trustchain = useSelector(trustchainSelector);
const memberCredentials = useSelector(memberCredentialsSelector);
- const errorHandler = useLifeCycle();
+ const { handleError } = useLifeCycle();
function fetchMembers() {
- if (!trustchain || !memberCredentials) {
- throw new Error("Trustchain or MemberCredentials is falsy");
+ if (!memberCredentials) {
+ return;
+ }
+ if (!trustchain) {
+ throw new TrustchainNotFound();
}
return sdk.getMembers(trustchain, memberCredentials);
@@ -32,13 +36,14 @@ export function useGetMembers() {
refetchOnReconnect: true,
refetchOnWindowFocus: true,
retry: false,
+ enabled: !!trustchain && !!memberCredentials,
});
useEffect(() => {
if (isErrorGetMembers) {
- errorHandler.handleError(getMembersError);
+ handleError(getMembersError);
}
- }, [errorHandler, getMembersError, isErrorGetMembers]);
+ }, [handleError, getMembersError, isErrorGetMembers]);
return {
isMembersLoading: isMembersLoading,
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInstanceName.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInstanceName.ts
new file mode 100644
index 000000000000..e0bf04771251
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInstanceName.ts
@@ -0,0 +1,14 @@
+import os from "os";
+
+const platformMap: Record = {
+ darwin: "Mac",
+ win32: "Windows",
+ linux: "Linux",
+};
+
+export function useInstanceName(): string {
+ const platform = os.platform();
+ const hostname = os.hostname();
+ const name = `${platformMap[platform] || platform}${hostname ? " " + hostname : ""}`;
+ return name;
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWalletSyncAnalytics.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts
similarity index 66%
rename from apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWalletSyncAnalytics.ts
rename to apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts
index ee8bd109bb82..c7a6af7acb63 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWalletSyncAnalytics.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncAnalytics.ts
@@ -4,7 +4,7 @@ import { Step } from "~/renderer/reducers/walletSync";
export enum AnalyticsPage {
ManageBackup = "Manage Backup",
ConfirmDeleteBackup = "Confirm Delete Backup",
- BackupDeleted = "Backup Deleted",
+ BackupDeleted = "delete backup success",
BackupDeletionError = "Backup Deletion Error",
ManageInstances = "Manage synchronized instances",
@@ -13,34 +13,42 @@ export enum AnalyticsPage {
InstanceRemovalSuccess = "Instance removal success",
Unsecured = "Remove instance wrong device connected",
AutoRemove = "Remove current instance",
+ AlreadySecuredSameSeed = "App already secured with this Ledger",
+ AlreadySecuredOtherSeed = "You can’t use this Ledger to Sync",
- Activation = "Activate Wallet Sync",
- DeviceActionActivation = "Device Action Activate Wallet Sync",
+ Activation = "Activate Ledger Sync",
+ DeviceActionActivation = "Device Action Activate Ledger Sync",
CreateOrSynchronizeTrustChain = "Create or synchronize with trustchain",
SynchronizationError = "Synchronization error",
SyncMethod = "Choose sync method",
+ MobileSync = "Sync from a mobile",
+ DesktopSync = "Sync from a desktop",
KeyCreated = "Backup creation success",
- KeyUpdated = "Backup update success",
+ KeyUpdated = "Sync apps success",
+ Loading = "Loading Trustchain",
SyncWithQR = "Sync with QR code",
PinCode = "Pin code",
+ PinCodeError = "Pin code error",
+ UnbackedError = "Trustchain initialization error",
SettingsGeneral = "Settings General",
- WalletSyncSettings = "Wallet Sync Settings",
+ LedgerSyncSettings = "Ledger Sync Settings",
}
-type Flow = "Wallet Sync";
+export type AnalyticsFlow = "Ledger Sync";
+export const AnalyticsFlow = "Ledger Sync";
type OnClickTrack = {
button: string;
page: string;
- flow?: Flow;
+ flow?: AnalyticsFlow;
};
type onActionTrack = {
button: string;
step: Step;
- flow: Flow;
+ flow?: AnalyticsFlow;
};
export const StepMappedToAnalytics: Record = {
@@ -53,15 +61,21 @@ export const StepMappedToAnalytics: Record = {
[Step.CreateOrSynchronize]: AnalyticsPage.Activation,
[Step.DeviceAction]: AnalyticsPage.DeviceActionActivation,
[Step.CreateOrSynchronizeTrustChain]: AnalyticsPage.CreateOrSynchronizeTrustChain,
+ [Step.ActivationLoading]: AnalyticsPage.Loading,
[Step.ActivationFinal]: AnalyticsPage.KeyCreated,
[Step.SynchronizationFinal]: AnalyticsPage.KeyUpdated,
[Step.SynchronizationError]: AnalyticsPage.SynchronizationError,
+ [Step.AlreadySecuredSameSeed]: AnalyticsPage.AlreadySecuredSameSeed,
+ [Step.AlreadySecuredOtherSeed]: AnalyticsPage.AlreadySecuredOtherSeed,
//Synchronize
[Step.SynchronizeMode]: AnalyticsPage.SyncMethod,
[Step.SynchronizeWithQRCode]: AnalyticsPage.SyncWithQR,
+ [Step.SynchronizeLoading]: AnalyticsPage.Loading,
[Step.PinCode]: AnalyticsPage.PinCode,
+ [Step.PinCodeError]: AnalyticsPage.PinCodeError,
[Step.Synchronized]: AnalyticsPage.KeyUpdated,
+ [Step.UnbackedError]: AnalyticsPage.UnbackedError,
//ManageInstances
[Step.SynchronizedInstances]: AnalyticsPage.ManageInstances,
@@ -72,11 +86,20 @@ export const StepMappedToAnalytics: Record = {
[Step.InstanceSuccesfullyDeleted]: AnalyticsPage.InstanceRemovalSuccess,
[Step.InstanceErrorDeletion]: AnalyticsPage.ManageInstances,
- //walletSyncActivated
- [Step.WalletSyncActivated]: AnalyticsPage.WalletSyncSettings,
+ //LedgerSyncActivated
+ [Step.LedgerSyncActivated]: AnalyticsPage.LedgerSyncSettings,
};
-export function useWalletSyncAnalytics() {
+export const StepsOutsideFlow: Step[] = [
+ Step.LedgerSyncActivated,
+ Step.ManageBackup,
+ Step.AutoRemoveInstance,
+ Step.UnsecuredLedger,
+ Step.BackupDeletionError,
+ Step.SynchronizedInstances,
+];
+
+export function useLedgerSyncAnalytics() {
const onClickTrack = ({ button, page, flow }: OnClickTrack) => {
track("button_clicked2", { button, page, flow });
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncInfo.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncInfo.ts
index 1afc9da813fc..24d390df3a41 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncInfo.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLedgerSyncInfo.ts
@@ -6,8 +6,14 @@ import getCloudSyncApi, {
} from "@ledgerhq/live-wallet/cloudsync/api";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
+import { trustchainSelector } from "@ledgerhq/trustchain/store";
+import { useSelector } from "react-redux";
+import { walletSelector } from "~/renderer/reducers/wallet";
export function useLedgerSyncInfo() {
+ const trustchain = useSelector(trustchainSelector);
+ const walletState = useSelector(walletSelector);
+
const featureWalletSync = useFeature("lldWalletSync");
const { trustchainApiBaseUrl, cloudSyncApiBaseUrl } = getWalletSyncEnvironmentParams(
featureWalletSync?.params?.environment,
@@ -23,10 +29,16 @@ export function useLedgerSyncInfo() {
},
];
- return useQueries({
+ const statusQuery = useQueries({
queries: QUERIES,
combine: combineData,
});
+
+ return {
+ statusQuery,
+ trustchain,
+ walletState,
+ };
}
function combineData(results: UseQueryResult[]) {
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLoadingStep.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLoadingStep.ts
new file mode 100644
index 000000000000..75b9c1a1b592
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useLoadingStep.ts
@@ -0,0 +1,43 @@
+import { useEffect, useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
+import { setFlow } from "~/renderer/actions/walletSync";
+import { walletSyncFlowSelector, walletSyncNextStepSelector } from "~/renderer/reducers/walletSync";
+import { useWalletSyncUserState } from "../components/WalletSyncContext";
+import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
+
+export function useLoadingStep() {
+ const dispatch = useDispatch();
+ const [waitedWatchLoop, setWaitedWatchLoop] = useState(false);
+ const { visualPending } = useWalletSyncUserState();
+ const nextStep = useSelector(walletSyncNextStepSelector);
+ const flow = useSelector(walletSyncFlowSelector);
+ const featureWalletSync = useFeature("lldWalletSync");
+ const initialTimeout = featureWalletSync?.params?.watchConfig?.initialTimeout || 1000;
+ const visualPendingTimeout = 1000;
+
+ useEffect(() => {
+ const timeout = setTimeout(
+ () => {
+ setWaitedWatchLoop(true);
+ },
+ initialTimeout + visualPendingTimeout + 500,
+ );
+
+ return () => {
+ clearTimeout(timeout);
+ };
+ }, [initialTimeout]);
+
+ useEffect(() => {
+ if (waitedWatchLoop && !visualPending && nextStep) {
+ dispatch(
+ setFlow({
+ flow,
+ step: nextStep,
+ nextStep: null,
+ hasTrustchainBeenCreated: null,
+ }),
+ );
+ }
+ }, [waitedWatchLoop, visualPending, dispatch, flow, nextStep]);
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useQRCode.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useQRCode.ts
index 8060a274b69f..54bf875c2282 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useQRCode.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useQRCode.ts
@@ -1,15 +1,31 @@
import { useCallback, useState } from "react";
import { createQRCodeHostInstance } from "@ledgerhq/trustchain/qrcode/index";
-import { InvalidDigitsError } from "@ledgerhq/trustchain/errors";
+import {
+ InvalidDigitsError,
+ NoTrustchainInitialized,
+ QRCodeWSClosed,
+ TrustchainAlreadyInitialized,
+} from "@ledgerhq/trustchain/errors";
+import { MemberCredentials } from "@ledgerhq/trustchain/types";
import { useDispatch, useSelector } from "react-redux";
import { setFlow, setQrCodePinCode } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { trustchainSelector, memberCredentialsSelector } from "@ledgerhq/trustchain/store";
+import {
+ trustchainSelector,
+ memberCredentialsSelector,
+ setTrustchain,
+} from "@ledgerhq/trustchain/store";
import { useTrustchainSdk } from "./useTrustchainSdk";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
+import { useMutation, useQueryClient } from "@tanstack/react-query";
+import { QueryKey } from "./type.hooks";
+import { useInstanceName } from "./useInstanceName";
+
+const MIN_TIME_TO_REFRESH = 30_000;
export function useQRCode() {
+ const queryClient = useQueryClient();
const dispatch = useDispatch();
const trustchain = useSelector(trustchainSelector);
const memberCredentials = useSelector(memberCredentialsSelector);
@@ -18,53 +34,79 @@ export function useQRCode() {
const { trustchainApiBaseUrl } = getWalletSyncEnvironmentParams(
featureWalletSync?.params?.environment,
);
- const [isLoading, setIsLoading] = useState(false);
const [url, setUrl] = useState(null);
- const [error, setError] = useState(null);
+ const memberName = useInstanceName();
const goToActivation = useCallback(() => {
dispatch(setFlow({ flow: Flow.Activation, step: Step.DeviceAction }));
}, [dispatch]);
- const startQRCodeProcessing = useCallback(() => {
- if (!trustchain || !memberCredentials) return;
+ const { mutate, isPending, error } = useMutation({
+ mutationFn: (memberCredentials: MemberCredentials) =>
+ createQRCodeHostInstance({
+ trustchainApiBaseUrl,
+ onDisplayQRCode: url => {
+ setUrl(url);
+ },
+ onDisplayDigits: digits => {
+ dispatch(setQrCodePinCode(digits));
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.PinCode }));
+ },
+ addMember: async member => {
+ if (trustchain) {
+ await sdk.addMember(trustchain, memberCredentials, member);
+ return trustchain;
+ }
+ throw new NoTrustchainInitialized();
+ },
+ memberCredentials,
+ memberName,
+ initialTrustchainId: trustchain?.rootId,
+ }),
+
+ // Don't use retry here because it always uses a delay despite setting it to 0
+ onError(e) {
+ if (e instanceof QRCodeWSClosed) {
+ const { time } = e as unknown as { time: number };
+ if (time >= MIN_TIME_TO_REFRESH) startQRCodeProcessing();
+ }
+ if (e instanceof InvalidDigitsError) {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.PinCodeError }));
+ }
+ if (e instanceof NoTrustchainInitialized) {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.UnbackedError }));
+ }
+ if (e instanceof TrustchainAlreadyInitialized) {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeWithQRCode }));
+ }
+ },
- setError(null);
- setIsLoading(true);
- createQRCodeHostInstance({
- trustchainApiBaseUrl,
- onDisplayQRCode: url => {
- setUrl(url);
- setIsLoading(false);
- },
- onDisplayDigits: digits => {
- dispatch(setQrCodePinCode(digits));
- dispatch(setFlow({ flow: Flow.Synchronize, step: Step.PinCode }));
- },
- addMember: async member => {
- await sdk.addMember(trustchain, memberCredentials, member);
- return trustchain;
- },
- })
- .catch(e => {
- if (e instanceof InvalidDigitsError) {
- return;
- }
- setError(e);
- setIsLoading(false);
- })
- .then(() => {
- setUrl(null);
- dispatch(setQrCodePinCode(null));
- setIsLoading(false);
- dispatch(setFlow({ flow: Flow.Synchronize, step: Step.Synchronized }));
- });
- }, [trustchainApiBaseUrl, trustchain, memberCredentials, dispatch, sdk]);
+ onSuccess(newTrustchain) {
+ if (newTrustchain) {
+ dispatch(setTrustchain(newTrustchain));
+ }
+ dispatch(
+ setFlow({
+ flow: Flow.Synchronize,
+ step: Step.SynchronizeLoading,
+ nextStep: Step.Synchronized,
+ hasTrustchainBeenCreated: false,
+ }),
+ );
+ queryClient.invalidateQueries({ queryKey: [QueryKey.getMembers] });
+ setUrl(null);
+ dispatch(setQrCodePinCode(null));
+ },
+ });
+
+ const startQRCodeProcessing = useCallback(() => {
+ if (memberCredentials) mutate(memberCredentials);
+ }, [mutate, memberCredentials]);
return {
url,
error,
- isLoading,
+ isLoading: isPending,
startQRCodeProcessing,
goToActivation,
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRemoveMember.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRemoveMember.ts
index add427798db3..4caa5eb26a2b 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRemoveMember.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRemoveMember.ts
@@ -6,8 +6,8 @@ import {
import { useDispatch, useSelector } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { useTrustchainSdk, runWithDevice } from "./useTrustchainSdk";
-import { TrustchainMember, Trustchain, MemberCredentials } from "@ledgerhq/trustchain/types";
+import { useTrustchainSdk } from "./useTrustchainSdk";
+import { TrustchainMember, Trustchain } from "@ledgerhq/trustchain/types";
import { useCallback, useEffect, useRef, useState } from "react";
import { TrustchainNotAllowed } from "@ledgerhq/trustchain/errors";
@@ -51,20 +51,24 @@ export function useRemoveMember({ device, member }: Props) {
const removeMember = useCallback(
async (member: TrustchainMember) => {
try {
- await runWithDevice(deviceRef.current?.deviceId, async transport => {
- const newTrustchain = await sdkRef.current.removeMember(
- transport,
- trustchainRef.current as Trustchain,
- memberCredentialsRef.current as MemberCredentials,
- member,
- {
- onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
- onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
- },
- );
+ if (!deviceRef.current) {
+ throw new Error("Device not found");
+ }
+ if (!trustchainRef.current || !memberCredentialsRef.current) {
+ throw new Error("trustchain or memberCredentials is not set");
+ }
+ const newTrustchain = await sdkRef.current.removeMember(
+ deviceRef.current.deviceId,
+ trustchainRef.current,
+ memberCredentialsRef.current,
+ member,
+ {
+ onStartRequestUserInteraction: () => setUserDeviceInteraction(true),
+ onEndRequestUserInteraction: () => setUserDeviceInteraction(false),
+ },
+ );
- transitionToNextScreen(newTrustchain);
- });
+ transitionToNextScreen(newTrustchain);
} catch (error) {
if (error instanceof Error) setError(error);
if (error instanceof TrustchainNotAllowed) {
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
index a30560471989..005b22b69803 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useTrustchainSdk.ts
@@ -1,10 +1,7 @@
-import os from "os";
-import { from, lastValueFrom } from "rxjs";
import { useMemo } from "react";
import { getEnv } from "@ledgerhq/live-env";
import { getSdk } from "@ledgerhq/trustchain/index";
import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
-import Transport from "@ledgerhq/hw-transport";
import { trustchainLifecycle } from "@ledgerhq/live-wallet/walletsync/index";
import { useStore } from "react-redux";
import { walletSelector } from "~/renderer/reducers/wallet";
@@ -12,19 +9,7 @@ import { walletSyncStateSelector } from "@ledgerhq/live-wallet/store";
import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
-
-export function runWithDevice(
- deviceId: string | undefined,
- fn: (transport: Transport) => Promise,
-): Promise {
- return lastValueFrom(withDevice(deviceId || "")(transport => from(fn(transport))));
-}
-
-const platformMap: Record = {
- darwin: "Mac",
- win32: "Windows",
- linux: "Linux",
-};
+import { useInstanceName } from "./useInstanceName";
let sdkInstance: TrustchainSDK | null = null;
@@ -33,14 +18,14 @@ export function useTrustchainSdk() {
const { trustchainApiBaseUrl, cloudSyncApiBaseUrl } = getWalletSyncEnvironmentParams(
featureWalletSync?.params?.environment,
);
+ const name = useInstanceName();
const isMockEnv = !!getEnv("MOCK");
+
const defaultContext = useMemo(() => {
const applicationId = 16;
- const platform = os.platform();
- const hash = getEnv("USER_ID").slice(0, 5);
- const name = `${platformMap[platform] || platform}${hash ? " " + hash : ""}`;
return { applicationId, name, apiBaseUrl: trustchainApiBaseUrl };
- }, [trustchainApiBaseUrl]);
+ }, [trustchainApiBaseUrl, name]);
+
const store = useStore();
const lifecycle = useMemo(
() =>
@@ -52,7 +37,7 @@ export function useTrustchainSdk() {
);
if (sdkInstance === null) {
- sdkInstance = getSdk(isMockEnv, defaultContext, lifecycle);
+ sdkInstance = getSdk(isMockEnv, defaultContext, withDevice, lifecycle);
}
return sdkInstance;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWatchWalletSync.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWatchWalletSync.ts
index f49c95e7802a..48260ce2bca6 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWatchWalletSync.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useWatchWalletSync.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useDispatch, useSelector, useStore } from "react-redux";
import noop from "lodash/noop";
import { CloudSyncSDK } from "@ledgerhq/live-wallet/cloudsync/index";
@@ -120,16 +120,17 @@ export function useWatchWalletSync(): WalletSyncUserState {
const [visualPending, setVisualPending] = useState(true);
const [walletSyncError, setWalletSyncError] = useState(null);
- const [onUserRefresh, setOnUserRefresh] = useState<() => void>(() => noop);
+ const onUserRefreshRef = useRef<() => void>(noop);
const state = useMemo(
- () => ({ visualPending, walletSyncError, onUserRefresh }),
- [visualPending, walletSyncError, onUserRefresh],
+ () => ({ visualPending, walletSyncError, onUserRefresh: onUserRefreshRef.current }),
+ [visualPending, walletSyncError],
);
// pull and push wallet sync loop
useEffect(() => {
- if (!trustchain || !memberCredentials) {
- setOnUserRefresh(() => noop);
+ const canNotRunWatchLoop = !featureWalletSync?.enabled || !trustchain || !memberCredentials;
+ if (canNotRunWatchLoop) {
+ onUserRefreshRef.current = noop;
setVisualPending(false);
setWalletSyncError(null);
return;
@@ -158,7 +159,7 @@ export function useWatchWalletSync(): WalletSyncUserState {
onTrustchainRefreshNeeded,
});
- setOnUserRefresh(() => onUserRefreshIntent);
+ onUserRefreshRef.current = onUserRefreshIntent;
return unsubscribe;
}, [
@@ -169,7 +170,7 @@ export function useWatchWalletSync(): WalletSyncUserState {
memberCredentials,
onTrustchainRefreshNeeded,
saveUpdate,
- featureWalletSync?.params?.watchConfig,
+ featureWalletSync,
]);
return state;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/walletSync.hooks.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/walletSync.hooks.ts
index d815533a74b9..d897437a2fd6 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/walletSync.hooks.ts
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/walletSync.hooks.ts
@@ -9,15 +9,18 @@ import {
TrustchainOutdated,
} from "@ledgerhq/trustchain/errors";
import { useRestoreTrustchain } from "./useRestoreTrustchain";
+import { useTrustchainSdk } from "./useTrustchainSdk";
export const useLifeCycle = () => {
const dispatch = useDispatch();
+ const sdk = useTrustchainSdk();
const { refetch: restoreTrustchain } = useRestoreTrustchain();
function reset() {
dispatch(resetTrustchainStore());
dispatch(setFlow({ flow: Flow.Activation, step: Step.CreateOrSynchronize }));
+ sdk.invalidateJwt();
}
const includesErrorActions: { [key: string]: () => void } = {
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/01-CreateOrSynchronizeStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/01-CreateOrSynchronizeStep.tsx
index e68169e6f0ca..338e7847e2dc 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/01-CreateOrSynchronizeStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/01-CreateOrSynchronizeStep.tsx
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
import { useTheme } from "styled-components";
import ButtonV3 from "~/renderer/components/ButtonV3";
import TrackPage from "~/renderer/analytics/TrackPage";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
import { LogoWrapper } from "../../components/LogoWrapper";
type Props = {
@@ -18,7 +18,7 @@ export default function CreateOrSynchronizeStep({ goToCreateBackup, goToSync }:
return (
-
+
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/02-DeviceActionStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/02-DeviceActionStep.tsx
index c86afe2cb7a4..82b66a720e40 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/02-DeviceActionStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/02-DeviceActionStep.tsx
@@ -1,14 +1,11 @@
import React from "react";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
import OpenOrInstallTrustChainApp from "../DeviceActions/openOrInstall";
-import { useInitMemberCredentials } from "../../hooks/useInitMemberCredentials";
type Props = {
goNext: (device: Device) => void;
};
export default function DeviceActionStep({ goNext }: Props) {
- useInitMemberCredentials();
-
return ;
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-LoadingStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-LoadingStep.tsx
new file mode 100644
index 000000000000..c1602f7c3eae
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-LoadingStep.tsx
@@ -0,0 +1,25 @@
+import React from "react";
+import Loading from "../../components/LoadingStep";
+import { useTranslation } from "react-i18next";
+import { AnalyticsFlow, AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
+import TrackPage from "~/renderer/analytics/TrackPage";
+import { useLoadingStep } from "../../hooks/useLoadingStep";
+import { walletSyncHasTrustchainBeenCreatedSelector } from "~/renderer/reducers/walletSync";
+import { useSelector } from "react-redux";
+
+export default function ActivationLoadingStep() {
+ useLoadingStep();
+ const hasTrustchainBeenCreated = useSelector(walletSyncHasTrustchainBeenCreatedSelector);
+ const { t } = useTranslation();
+ const title = "walletSync.loading.title";
+ const subtitle = hasTrustchainBeenCreated
+ ? "walletSync.loading.activation"
+ : "walletSync.loading.synch";
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-ActivationFinalStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/05-ActivationFinalStep.tsx
similarity index 86%
rename from apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-ActivationFinalStep.tsx
rename to apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/05-ActivationFinalStep.tsx
index 30d092a749d8..169aba5f15ff 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/04-ActivationFinalStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/05-ActivationFinalStep.tsx
@@ -4,7 +4,11 @@ import { useTranslation } from "react-i18next";
import { useDispatch } from "react-redux";
import { setDrawerVisibility, setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import {
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+ AnalyticsFlow,
+} from "../../hooks/useLedgerSyncAnalytics";
type Props = {
isNewBackup: boolean;
@@ -16,14 +20,14 @@ export default function ActivationFinalStep({ isNewBackup }: Props) {
const title = isNewBackup ? "walletSync.success.backup.title" : "walletSync.success.synch.title";
const desc = isNewBackup ? "walletSync.success.backup.desc" : "walletSync.success.synch.desc";
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const goToSync = () => {
dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeWithQRCode }));
onClickTrack({
button: "Sync with another Ledger Live",
page: isNewBackup ? AnalyticsPage.KeyCreated : AnalyticsPage.KeyUpdated,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
@@ -32,7 +36,7 @@ export default function ActivationFinalStep({ isNewBackup }: Props) {
onClickTrack({
button: "Close",
page: isNewBackup ? AnalyticsPage.KeyCreated : AnalyticsPage.KeyUpdated,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
return (
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/05-ActivationOrSyncError.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/06-ActivationOrSyncError.tsx
similarity index 100%
rename from apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/05-ActivationOrSyncError.tsx
rename to apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/06-ActivationOrSyncError.tsx
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/index.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/index.tsx
index f863aae5740f..ecf2fa2a1792 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Activation/index.tsx
@@ -1,41 +1,59 @@
-import React, { useState } from "react";
+import React, { forwardRef, useImperativeHandle, useState } from "react";
import { useDispatch } from "react-redux";
import { Flex } from "@ledgerhq/react-ui";
import { Flow, Step } from "~/renderer/reducers/walletSync";
import { setFlow } from "~/renderer/actions/walletSync";
-import { useFlows } from "../../hooks/useFlows";
+import { FlowOptions, useFlows } from "../../hooks/useFlows";
import CreateOrSynchronizeStep from "./01-CreateOrSynchronizeStep";
import DeviceActionStep from "./02-DeviceActionStep";
import ActivationOrSynchroWithTrustchain from "./03-ActivationOrSynchroWithTrustchain";
-import ActivationFinalStep from "./04-ActivationFinalStep";
+import LoadingStep from "./04-LoadingStep";
+import ActivationFinalStep from "./05-ActivationFinalStep";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
-import ErrorStep from "./05-ActivationOrSyncError";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import ErrorStep from "./06-ActivationOrSyncError";
+import {
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+ AnalyticsFlow,
+} from "../../hooks/useLedgerSyncAnalytics";
+import { BackRef, BackProps } from "../router";
-const WalletSyncActivation = () => {
+const WalletSyncActivation = forwardRef((_props, ref) => {
const dispatch = useDispatch();
const [device, setDevice] = useState(null);
- const { currentStep, goToNextScene } = useFlows();
+ const { currentStep, goToNextScene, goToPreviousScene, goToWelcomeScreenWalletSync } = useFlows();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ useImperativeHandle(ref, () => ({
+ goBack,
+ }));
+
+ const goBack = () => {
+ if (currentStep === FlowOptions[Flow.Activation].steps[1]) {
+ goToWelcomeScreenWalletSync();
+ } else {
+ goToPreviousScene();
+ }
+ };
const goToSync = () => {
dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeMode }));
onClickTrack({
- button: "Already created a key?",
+ button: "Already synced a Ledger Live app?",
page: AnalyticsPage.Activation,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
const goToCreateBackup = () => {
goToNextScene();
onClickTrack({
- button: "create your backup",
+ button: "Sync your accounts",
page: AnalyticsPage.Activation,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
@@ -53,10 +71,13 @@ const WalletSyncActivation = () => {
return ;
case Step.CreateOrSynchronizeTrustChain:
return ;
+ case Step.ActivationLoading:
+ return ;
case Step.ActivationFinal:
return ;
case Step.SynchronizationFinal:
return ;
+
case Step.SynchronizationError:
return ;
}
@@ -74,6 +95,6 @@ const WalletSyncActivation = () => {
{getStep()}
);
-};
-
+});
+WalletSyncActivation.displayName = "WalletSyncActivation";
export default WalletSyncActivation;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/FollowStepsOnDevice.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/FollowStepsOnDevice.tsx
index ea57db6708b1..79b612228655 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/FollowStepsOnDevice.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/FollowStepsOnDevice.tsx
@@ -17,9 +17,11 @@ const getProductName = (modelId: DeviceModelId) =>
getDeviceModel(modelId)?.productName.replace("Ledger", "").trimStart() || modelId;
export default function FollowStepsOnDevice({ modelId, isDeviceBlocker }: Props) {
- const { theme } = useTheme();
+ const { colors } = useTheme();
+ const theme = colors.palette.type;
const { t } = useTranslation();
const wording = getProductName(modelId);
+
return (
<>
{isDeviceBlocker ? : null}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Manage/index.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Manage/index.tsx
index c3041eec3feb..119438bde296 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Manage/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Manage/index.tsx
@@ -10,7 +10,7 @@ import styled from "styled-components";
import { useInstances } from "../ManageInstances/useInstances";
import { useLifeCycle } from "../../hooks/walletSync.hooks";
import TrackPage from "~/renderer/analytics/TrackPage";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
import { useLedgerSyncInfo } from "../../hooks/useLedgerSyncInfo";
import { AlertError } from "../../components/AlertError";
import { AlertLedgerSyncDown } from "../../components/AlertLedgerSyncDown";
@@ -24,27 +24,29 @@ const WalletSyncManage = () => {
const { t } = useTranslation();
useLifeCycle();
- const { error: ledgerSyncError, isError: isLedgerSyncError } = useLedgerSyncInfo();
+ const {
+ statusQuery: { error: ledgerSyncError, isError: isLedgerSyncError },
+ } = useLedgerSyncInfo();
const { instances, isLoading, hasError, error: membersError } = useInstances();
const dispatch = useDispatch();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const goToSync = () => {
dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeMode }));
- onClickTrack({ button: "Synchronize", page: AnalyticsPage.WalletSyncSettings });
+ onClickTrack({ button: "Synchronize", page: AnalyticsPage.LedgerSyncSettings });
};
const goToManageBackup = () => {
dispatch(setFlow({ flow: Flow.ManageBackup, step: Step.ManageBackup }));
- onClickTrack({ button: "Manage Backup", page: AnalyticsPage.WalletSyncSettings });
+ onClickTrack({ button: "Manage Key", page: AnalyticsPage.LedgerSyncSettings });
};
const goToManageInstances = () => {
dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.SynchronizedInstances }));
- onClickTrack({ button: "Manage Instances", page: AnalyticsPage.WalletSyncSettings });
+ onClickTrack({ button: "Manage Instances", page: AnalyticsPage.LedgerSyncSettings });
};
const Options: OptionProps[] = [
@@ -78,7 +80,7 @@ const WalletSyncManage = () => {
return (
-
+
{t("walletSync.title")}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/01-ManageBackupStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/01-ManageBackupStep.tsx
index 71bd59a2b5f5..9cdfdf24e6dd 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/01-ManageBackupStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/01-ManageBackupStep.tsx
@@ -5,17 +5,17 @@ import { Card } from "../../components/Card";
import styled, { useTheme } from "styled-components";
import { rgba } from "~/renderer/styles/helpers";
import { ManageBackupStepProps } from "./types";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
import TrackPage from "~/renderer/analytics/TrackPage";
export default function ManageBackupStep({ goToDeleteBackup }: ManageBackupStepProps) {
const { t } = useTranslation();
const { colors } = useTheme();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const handleGoDeleteBackup = () => {
- onClickTrack({ button: "delete data", page: AnalyticsPage.ManageBackup });
+ onClickTrack({ button: "Delete backup", page: AnalyticsPage.ManageBackup });
goToDeleteBackup();
};
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/02-DeleteBackupStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/02-DeleteBackupStep.tsx
index 53ea92b9507b..b4b6bc46a5f7 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/02-DeleteBackupStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/02-DeleteBackupStep.tsx
@@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
import { DeleteBackupStepProps } from "./types";
import { Flex, Text } from "@ledgerhq/react-ui";
import ButtonV3 from "~/renderer/components/ButtonV3";
-import { useWalletSyncAnalytics, AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import { useLedgerSyncAnalytics, AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
import TrackPage from "~/renderer/analytics/TrackPage";
import { useDestroyTrustchain } from "../../hooks/useDestroyTrustchain";
@@ -12,7 +12,7 @@ export default function DeleteBackupStep({ cancel }: DeleteBackupStepProps) {
const { deleteMutation } = useDestroyTrustchain();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const handleDeleteBackup = async () => {
onClickTrack({ button: "delete", page: AnalyticsPage.ConfirmDeleteBackup });
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/03-FinalStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/03-FinalStep.tsx
index 244fca4a4591..2724e838d8ce 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/03-FinalStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/03-FinalStep.tsx
@@ -4,16 +4,39 @@ import { useTranslation } from "react-i18next";
import { Flex } from "@ledgerhq/react-ui";
import { Error } from "../../components/Error";
import { BackupDeletedProps } from "./types";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
+import { useDispatch } from "react-redux";
+import { setDrawerVisibility } from "~/renderer/actions/walletSync";
export default function BackupDeleted({ isSuccessful }: BackupDeletedProps) {
const { t } = useTranslation();
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const dispatch = useDispatch();
+
+ const onClose = () => {
+ dispatch(setDrawerVisibility(false));
+ onClickTrack({
+ button: "Close",
+ page: AnalyticsPage.BackupDeleted,
+ });
+ };
+
return (
{isSuccessful ? (
-
+
) : (
-
+
)}
);
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/index.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/index.tsx
index cd288ff83848..b4625811ba65 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageBackup/index.tsx
@@ -22,7 +22,7 @@ const WalletSyncManageBackup = forwardRef((_props, ref) => {
const goBack = () => {
if (currentStep === FlowOptions[Flow.ManageBackup].steps[1]) {
- goToWelcomeScreenWalletSync(true);
+ goToWelcomeScreenWalletSync();
} else {
goToPreviousScene();
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/01-ManageInstancesStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/01-ManageInstancesStep.tsx
index 1560a3bef1d2..8784d72bbf1d 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/01-ManageInstancesStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/01-ManageInstancesStep.tsx
@@ -1,7 +1,7 @@
import { Flex, Text } from "@ledgerhq/react-ui";
import React from "react";
import { useTranslation } from "react-i18next";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
import TrackPage from "~/renderer/analytics/TrackPage";
import { TinyCard } from "../../components/TinyCard";
import { useInstances } from "./useInstances";
@@ -23,7 +23,7 @@ export default function ManageInstancesStep({ goToDeleteInstance }: Props) {
const dispatch = useDispatch();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const handleGoDeleteInstance = (instance: TrustchainMember) => {
onClickTrack({ button: "remove instance", page: AnalyticsPage.ManageInstances });
@@ -68,6 +68,7 @@ export default function ManageInstancesStep({ goToDeleteInstance }: Props) {
const List = styled(Flex)`
overflow-y: auto;
+ padding-bottom: 12%;
max-height: calc(100vh - 12%);
::-webkit-scrollbar {
width: 0;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionError.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionError.tsx
index 049cebe7e48f..dcf7d843598c 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionError.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionError.tsx
@@ -6,7 +6,7 @@ import styled, { useTheme } from "styled-components";
import { setFlow } from "~/renderer/actions/walletSync";
import ButtonV3 from "~/renderer/components/ButtonV3";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
import TrackPage from "~/renderer/analytics/TrackPage";
const Container = styled(Box)`
@@ -31,7 +31,7 @@ type Props = {
export const DeletionError = ({ error }: Props) => {
const dispatch = useDispatch();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const tryAgain = () => {
dispatch(setFlow({ flow: Flow.ManageInstances, step: Step.DeviceActionInstance }));
@@ -39,7 +39,7 @@ export const DeletionError = ({ error }: Props) => {
};
const goToDelete = () => {
dispatch(setFlow({ flow: Flow.ManageBackup, step: Step.ManageBackup }));
- onClickTrack({ button: "delete backup", page: errorConfig[error].analyticsPage });
+ onClickTrack({ button: "delete key", page: errorConfig[error].analyticsPage });
};
const understood = () => {
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalStep.tsx
index 28d6bb03594d..7b19e4b3d01f 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalStep.tsx
@@ -2,17 +2,37 @@ import React from "react";
import { Success } from "../../components/Success";
import { useTranslation } from "react-i18next";
import { FinalStepProps } from "./04-DeletionFinalErrorStep";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import {
+ AnalyticsFlow,
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+} from "../../hooks/useLedgerSyncAnalytics";
+import { setDrawerVisibility } from "~/renderer/actions/walletSync";
+import { useDispatch } from "react-redux";
export default function DeletionFinalStep({ instance }: FinalStepProps) {
const { t } = useTranslation();
const title = "walletSync.manageInstances.deleteInstanceSuccess";
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const dispatch = useDispatch();
+
+ const onClose = () => {
+ dispatch(setDrawerVisibility(false));
+ onClickTrack({
+ button: "Close",
+ page: AnalyticsPage.InstanceRemovalSuccess,
+ flow: AnalyticsFlow,
+ });
+ };
return (
);
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/index.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/index.tsx
index 8e8f4b0e0a8b..ce29ff8ba098 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/index.tsx
@@ -28,7 +28,7 @@ const WalletSyncManageInstances = forwardRef((_props, ref) =
const goBack = () => {
if (currentStep === FlowOptions[Flow.ManageInstances].steps[1]) {
- goToWelcomeScreenWalletSync(true);
+ goToWelcomeScreenWalletSync();
} else {
goToPreviousScene();
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/01-SyncModeStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/01-SyncModeStep.tsx
index e5e49f5b2429..d6867586be2e 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/01-SyncModeStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/01-SyncModeStep.tsx
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
import { Card } from "../../components/Card";
import styled, { useTheme } from "styled-components";
import TrackPage from "~/renderer/analytics/TrackPage";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
type Props = {
goToQRCode: () => void;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/02-QRCodeStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/02-QRCodeStep.tsx
index bb5299346ee9..d9fb3573f96a 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/02-QRCodeStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/02-QRCodeStep.tsx
@@ -1,48 +1,81 @@
-import React, { useEffect } from "react";
+import React, { useEffect, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
-import { Flex, Icons, Link, Text, NumberedList, InfiniteLoader } from "@ledgerhq/react-ui";
+import { Flex, Icons, Text, NumberedList, InfiniteLoader, TabSelector } from "@ledgerhq/react-ui";
import styled, { useTheme } from "styled-components";
import { rgba } from "~/renderer/styles/helpers";
import QRCode from "~/renderer/components/QRCode";
import { useQRCode } from "../../hooks/useQRCode";
import ErrorDisplay from "~/renderer/components/ErrorDisplay";
import TrackPage from "~/renderer/analytics/TrackPage";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import {
+ AnalyticsFlow,
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+} from "../../hooks/useLedgerSyncAnalytics";
+import { AnimatePresence, motion, useAnimation } from "framer-motion";
+
+const animation = {
+ opacity: [0, 1],
+ transition: { type: "spring", damping: 30, stiffness: 130 },
+};
+
+export enum Options {
+ MOBILE = "mobile",
+ DESKTOP = "desktop",
+}
export default function SynchWithQRCodeStep() {
const { t } = useTranslation();
- const { colors } = useTheme();
+ const controls = useAnimation();
+ const [currentOption, setCurrentOption] = useState(Options.MOBILE);
- const steps = [
- { element: t("walletSync.synchronize.qrCode.steps.step1") },
- {
- element: (
-
- ]}
- />
-
- ),
- },
- { element: t("walletSync.synchronize.qrCode.steps.step3") },
- ];
-
- const { goToActivation, startQRCodeProcessing, url, error, isLoading } = useQRCode();
+ const { startQRCodeProcessing, url, error, isLoading } = useQRCode();
console.log("url", url);
useEffect(() => {
startQRCodeProcessing();
+
+ controls.start({
+ x: ["10vw", "0vw"],
+ ...animation,
+ });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const handleSelectOption = (option: Options) => {
+ controls.start({
+ x: [currentOption === Options.MOBILE ? "-10vw" : "10vw", "0vw"],
+ ...animation,
+ });
+ setCurrentOption(option);
+
+ onClickTrack({
+ button: option,
+ page: AnalyticsPage.SyncWithQR,
+ flow: AnalyticsFlow,
+ });
+ };
+
+ const renderSwitch = () => {
+ switch (currentOption) {
+ case Options.MOBILE:
+ return (
+ <>
+
+
+ >
+ );
+ case Options.DESKTOP:
+ return (
+ <>
+
+
+ >
+ );
+ }
+ };
+
if (isLoading) {
@@ -65,66 +98,144 @@ export default function SynchWithQRCodeStep() {
>
{t("walletSync.synchronize.qrCode.title")}
-
+
+
+
+ {renderSwitch()}
+
+
+
+
+ );
+}
+
+const QRCodeComponent = ({ url }: { url: string | null }) => {
+ const { t } = useTranslation();
+ const { colors } = useTheme();
+
+ const steps = [
+ { element: t("walletSync.synchronize.qrCode.mobile.steps.step1") },
+ {
+ element: (
+
+ ]}
+ />
+
+ ),
+ },
+ { element: t("walletSync.synchronize.qrCode.mobile.steps.step3") },
+ ];
+
+ return (
+ <>
+
-
- {url && (
-
+
+
-
-
-
-
-
- )}
-
-
-
+
+
+ )}
+
+
+
+
+ {t("walletSync.synchronize.qrCode.mobile.description")}
+
+
+
+ >
+ );
+};
+
+const DesktopComponent = () => {
+ const { t } = useTranslation();
+ const { colors } = useTheme();
+
+ const steps = [
+ { element: t("walletSync.synchronize.qrCode.desktop.steps.step1") },
+ {
+ element: (
+
-
- {t("walletSync.synchronize.qrCode.description")}
-
-
-
-
-
- {t("walletSync.synchronize.qrCode.hint")}
-
-
-
-
+ ]}
+ />
+
+ ),
+ },
+ { element: t("walletSync.synchronize.qrCode.desktop.steps.step3") },
+ ];
+
+ return (
+
+
+ {t("walletSync.synchronize.qrCode.desktop.description")}
+
+
+
);
-}
+};
const MiddleContainer = styled(Flex)`
border-radius: 12px;
@@ -139,3 +250,10 @@ const Italic = styled(Text)`
`;
const IconContainer = styled(Flex)``;
+
+const AnimatedDiv = styled(motion.div)`
+ display: flex;
+ justify-content: center;
+ flex-direction: column;
+ align-items: center;
+`;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/03-PinCodeStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/03-PinCodeStep.tsx
index 1cbcfd348a32..20b504f6e707 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/03-PinCodeStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/03-PinCodeStep.tsx
@@ -5,7 +5,7 @@ import styled, { useTheme } from "styled-components";
import { useSelector } from "react-redux";
import { walletSyncQrCodePinCodeSelector } from "~/renderer/reducers/walletSync";
import TrackPage from "~/renderer/analytics/TrackPage";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
export default function PinCodeStep() {
const { t } = useTranslation();
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/04-SyncFinalStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/04-SyncFinalStep.tsx
index 36f6b2313631..ff88877ae101 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/04-SyncFinalStep.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/04-SyncFinalStep.tsx
@@ -1,13 +1,51 @@
import React from "react";
import { Success } from "../../components/Success";
import { useTranslation } from "react-i18next";
-import { AnalyticsPage } from "../../hooks/useWalletSyncAnalytics";
+import {
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+ AnalyticsFlow,
+} from "../../hooks/useLedgerSyncAnalytics";
+import { useDispatch } from "react-redux";
+import { setDrawerVisibility, setFlow } from "~/renderer/actions/walletSync";
+import { Flow, Step } from "~/renderer/reducers/walletSync";
export default function SyncFinalStep() {
const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
const title = "walletSync.success.synch.title";
const desc = "walletSync.success.synch.desc";
+
+ const onClose = () => {
+ dispatch(setDrawerVisibility(false));
+ onClickTrack({
+ button: "Close",
+ page: AnalyticsPage.KeyUpdated,
+ flow: AnalyticsFlow,
+ });
+ };
+
+ const goToSync = () => {
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeWithQRCode }));
+ onClickTrack({
+ button: "Sync with another Ledger Live",
+ page: AnalyticsPage.KeyUpdated,
+ flow: AnalyticsFlow,
+ });
+ };
+
return (
-
+
);
}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-PinCodeError.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-PinCodeError.tsx
new file mode 100644
index 000000000000..b95c380b0e8b
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-PinCodeError.tsx
@@ -0,0 +1,28 @@
+import React from "react";
+import { Error } from "../../components/Error";
+import { useTranslation } from "react-i18next";
+import { AnalyticsPage } from "../../hooks/useLedgerSyncAnalytics";
+import { useDispatch } from "react-redux";
+import { setFlow } from "~/renderer/actions/walletSync";
+import { Flow, Step } from "~/renderer/reducers/walletSync";
+
+export default function PinCodeErrorStep() {
+ const { t } = useTranslation();
+
+ const dispatch = useDispatch();
+
+ const title = "walletSync.synchronize.pinCode.error.title";
+ const desc = "walletSync.synchronize.pinCode.error.description";
+
+ return (
+
+ dispatch(setFlow({ flow: Flow.Synchronize, step: Step.SynchronizeWithQRCode }))
+ }
+ />
+ );
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-UnbackedError.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-UnbackedError.tsx
new file mode 100644
index 000000000000..352ea6ce0345
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/05-UnbackedError.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import { Error } from "../../components/Error";
+import { useTranslation } from "react-i18next";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
+import { useDispatch } from "react-redux";
+import { setFlow } from "~/renderer/actions/walletSync";
+import { Flow, Step } from "~/renderer/reducers/walletSync";
+
+export default function UnbackedError() {
+ const { t } = useTranslation();
+
+ const { onClickTrack } = useLedgerSyncAnalytics();
+ const dispatch = useDispatch();
+ const onClick = () => {
+ onClickTrack({
+ button: "Create enctryption key",
+ page: AnalyticsPage.UnbackedError,
+ });
+ dispatch(setFlow({ flow: Flow.Activation, step: Step.DeviceAction }));
+ };
+
+ return (
+
+ );
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/06-ActivationAlreadyCreatedSame.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/06-ActivationAlreadyCreatedSame.tsx
new file mode 100644
index 000000000000..e1147ee6ab97
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/06-ActivationAlreadyCreatedSame.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { setDrawerVisibility, setFlow } from "~/renderer/actions/walletSync";
+import { Flow, Step } from "~/renderer/reducers/walletSync";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
+import { Info } from "../../components/Info";
+
+export default function AlreadyCreatedWithSameSeedStep() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const understood = () => {
+ dispatch(setFlow({ flow: Flow.LedgerSyncActivated, step: Step.LedgerSyncActivated }));
+ onClickTrack({
+ button: "I Understand",
+ page: AnalyticsPage.AlreadySecuredSameSeed,
+ });
+ };
+
+ const onClose = () => {
+ dispatch(setDrawerVisibility(false));
+ onClickTrack({
+ button: "Close",
+ page: AnalyticsPage.AlreadySecuredSameSeed,
+ });
+ };
+ return (
+
+ );
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/07-ActivationAlreadyCreatedOther.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/07-ActivationAlreadyCreatedOther.tsx
new file mode 100644
index 000000000000..1b4107df2b24
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/07-ActivationAlreadyCreatedOther.tsx
@@ -0,0 +1,42 @@
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch } from "react-redux";
+import { setDrawerVisibility, setFlow } from "~/renderer/actions/walletSync";
+import { Flow, Step } from "~/renderer/reducers/walletSync";
+import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSyncAnalytics";
+import { Error } from "../../components/Error";
+
+export default function AlreadyCreatedOtherSeedStep() {
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const deleteKey = () => {
+ dispatch(setFlow({ flow: Flow.ManageBackup, step: Step.ManageBackup }));
+ onClickTrack({
+ button: "Delete my encryption key",
+ page: AnalyticsPage.AlreadySecuredOtherSeed,
+ });
+ };
+
+ const onClose = () => {
+ dispatch(setDrawerVisibility(false));
+ onClickTrack({
+ button: "close",
+ page: AnalyticsPage.AlreadySecuredOtherSeed,
+ });
+ };
+
+ return (
+
+ );
+}
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/index.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/index.tsx
index 4a228e1a46fc..1540604179e6 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/index.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/Synchronize/index.tsx
@@ -1,36 +1,58 @@
import { Flex } from "@ledgerhq/react-ui";
-import React from "react";
+import React, { forwardRef, useImperativeHandle } from "react";
import { useDispatch } from "react-redux";
import { setFlow } from "~/renderer/actions/walletSync";
import { Flow, Step } from "~/renderer/reducers/walletSync";
-import { useFlows } from "../../hooks/useFlows";
+import { FlowOptions, useFlows } from "../../hooks/useFlows";
import SynchronizeModeStep from "./01-SyncModeStep";
import SynchWithQRCodeStep from "./02-QRCodeStep";
import PinCodeStep from "./03-PinCodeStep";
import SyncFinalStep from "./04-SyncFinalStep";
-import { AnalyticsPage, useWalletSyncAnalytics } from "../../hooks/useWalletSyncAnalytics";
+import {
+ AnalyticsPage,
+ useLedgerSyncAnalytics,
+ AnalyticsFlow,
+} from "../../hooks/useLedgerSyncAnalytics";
+import PinCodeErrorStep from "./05-PinCodeError";
+import UnbackedErrorStep from "./05-UnbackedError";
+import { BackProps, BackRef } from "../router";
+import AlreadyCreatedWithSameSeedStep from "./06-ActivationAlreadyCreatedSame";
+import AlreadyCreatedOtherSeedStep from "./07-ActivationAlreadyCreatedOther";
+import ActivationLoadingStep from "../Activation/04-LoadingStep";
-const SynchronizeWallet = () => {
+const SynchronizeWallet = forwardRef((_props, ref) => {
const dispatch = useDispatch();
- const { currentStep, goToNextScene } = useFlows();
- const { onClickTrack } = useWalletSyncAnalytics();
+ useImperativeHandle(ref, () => ({
+ goBack,
+ }));
+
+ const { currentStep, goToNextScene, goToPreviousScene, goToWelcomeScreenWalletSync } = useFlows();
+ const { onClickTrack } = useLedgerSyncAnalytics();
+
+ const goBack = () => {
+ if (currentStep === FlowOptions[Flow.Synchronize].steps[1]) {
+ goToWelcomeScreenWalletSync();
+ } else {
+ goToPreviousScene();
+ }
+ };
const startSyncWithDevice = () => {
dispatch(setFlow({ flow: Flow.Activation, step: Step.DeviceAction }));
onClickTrack({
- button: "With your Ledger",
+ button: "Use your Ledger",
page: AnalyticsPage.SyncMethod,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
const startSyncWithQRcode = () => {
goToNextScene();
onClickTrack({
- button: "Scan a QR code",
+ button: "Display QR code",
page: AnalyticsPage.SyncMethod,
- flow: "Wallet Sync",
+ flow: AnalyticsFlow,
});
};
@@ -48,23 +70,49 @@ const SynchronizeWallet = () => {
return ;
case Step.PinCode:
return ;
+
+ case Step.PinCodeError:
+ return ;
+
+ case Step.UnbackedError:
+ return ;
+
+ case Step.AlreadySecuredSameSeed:
+ return ;
+ case Step.AlreadySecuredOtherSeed:
+ return ;
+ case Step.SynchronizeLoading:
+ return ;
+
case Step.Synchronized:
return ;
}
};
+ const centeredItems = [
+ Step.Synchronized,
+ Step.PinCodeError,
+ Step.UnbackedError,
+ Step.AlreadySecuredSameSeed,
+ Step.AlreadySecuredOtherSeed,
+ ];
+
+ const withoutPaddingItems = [Step.SynchronizeLoading];
+
return (
{getStep()}
);
-};
+});
+
+SynchronizeWallet.displayName = "SynchronizeWallet";
export default SynchronizeWallet;
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/router.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/router.tsx
index 2f96895dd564..bb0cd9c11b3d 100644
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/router.tsx
+++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/router.tsx
@@ -6,6 +6,7 @@ import SynchronizeWallet from "./Synchronize";
import WalletSyncManageInstances from "./ManageInstances";
import WalletSyncActivation from "./Activation";
import WalletSyncManage from "./Manage";
+import { useInitMemberCredentials } from "../hooks/useInitMemberCredentials";
export interface BackRef {
goBack: () => void;
@@ -14,16 +15,17 @@ export interface BackRef {
export interface BackProps {}
export const WalletSyncRouter = forwardRef((_props, ref) => {
+ useInitMemberCredentials();
const walletSyncFlow = useSelector(walletSyncFlowSelector);
switch (walletSyncFlow) {
default:
case Flow.Activation:
- return ;
- case Flow.WalletSyncActivated:
+ return ;
+ case Flow.LedgerSyncActivated:
return ;
case Flow.Synchronize:
- return ;
+ return ;
case Flow.ManageBackup:
return ;
case Flow.ManageInstances:
diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/testHelper/helper.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/testHelper/helper.ts
deleted file mode 100644
index e3b477a838c0..000000000000
--- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/testHelper/helper.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { getSdk } from "@ledgerhq/trustchain/index";
-import { Flow, initialStateWalletSync, Step } from "~/renderer/reducers/walletSync";
-import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams";
-
-export const mockedSdk = getSdk(true, {
- applicationId: 12,
- name: "LLD Integration",
- apiBaseUrl: getWalletSyncEnvironmentParams("STAGING").trustchainApiBaseUrl,
-});
-
-export const walletSyncActivatedState = {
- ...initialStateWalletSync,
- flow: Flow.WalletSyncActivated,
- step: Step.WalletSyncActivated,
-};
-
-export const simpleTrustChain = {
- rootId: "rootId",
- deviceId: "deviceId",
- trustchainId: "trustchainId",
-};
diff --git a/apps/ledger-live-desktop/src/newArch/hooks/useOnScreen.ts b/apps/ledger-live-desktop/src/newArch/hooks/useOnScreen.ts
new file mode 100644
index 000000000000..1d46a4dc56da
--- /dev/null
+++ b/apps/ledger-live-desktop/src/newArch/hooks/useOnScreen.ts
@@ -0,0 +1,50 @@
+import React, { useEffect } from "react";
+
+interface InteractionObserverHookParams {
+ root?: React.RefObject;
+ target: React.RefObject;
+ onIntersect: Function;
+ threshold?: number;
+ rootMargin?: string;
+ enabled?: boolean;
+}
+
+/**
+ * Observe if target is getting into viewport
+ * (related to root. Root is document viewport if not given)
+ **/
+export function useOnScreen({
+ root,
+ target,
+ onIntersect,
+ threshold = 1.0,
+ rootMargin = "0px",
+ enabled = true,
+}: InteractionObserverHookParams) {
+ useEffect(() => {
+ if (!enabled) {
+ return;
+ }
+
+ const el = target && target.current;
+
+ if (!el) {
+ return;
+ }
+
+ const observer = new IntersectionObserver(
+ entries => entries.forEach(entry => entry.isIntersecting && onIntersect()),
+ {
+ root: root?.current ?? null,
+ rootMargin,
+ threshold,
+ },
+ );
+
+ observer.observe(el);
+
+ return () => {
+ observer.unobserve(el);
+ };
+ }, [enabled, root, rootMargin, threshold, target, onIntersect]);
+}
diff --git a/apps/ledger-live-desktop/src/renderer/App.tsx b/apps/ledger-live-desktop/src/renderer/App.tsx
index 7268993fbac7..6f261193bc3b 100644
--- a/apps/ledger-live-desktop/src/renderer/App.tsx
+++ b/apps/ledger-live-desktop/src/renderer/App.tsx
@@ -32,6 +32,7 @@ import { StorylyProvider } from "~/storyly/StorylyProvider";
import { CounterValuesStateRaw } from "@ledgerhq/live-countervalues/types";
import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
+import { AppDataStorageProvider } from "~/renderer/hooks/storage-provider/useAppDataStorage";
import { allowDebugReactQuerySelector } from "./reducers/settings";
const reloadApp = (event: KeyboardEvent) => {
@@ -77,30 +78,32 @@ const InnerApp = ({ initialCountervalues }: { initialCountervalues: CounterValue
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/ledger-live-desktop/src/renderer/Default.tsx b/apps/ledger-live-desktop/src/renderer/Default.tsx
index f1cb1d4ce0f0..649064c70530 100644
--- a/apps/ledger-live-desktop/src/renderer/Default.tsx
+++ b/apps/ledger-live-desktop/src/renderer/Default.tsx
@@ -6,7 +6,7 @@ import { useDispatch, useSelector } from "react-redux";
import TrackAppStart from "~/renderer/components/TrackAppStart";
import { LiveApp } from "~/renderer/screens/platform";
import { BridgeSyncProvider } from "~/renderer/bridge/BridgeSyncContext";
-import { WalletSyncProvider } from "~/newArch/features/WalletSync/components/WalletSyncContext";
+import { WalletSyncProvider } from "LLD/features/WalletSync/components/WalletSyncContext";
import { SyncNewAccounts } from "~/renderer/bridge/SyncNewAccounts";
import Box from "~/renderer/components/Box/Box";
import { useListenToHidDevices } from "./hooks/useListenToHidDevices";
@@ -76,7 +76,9 @@ const SyncOnboarding = lazy(() => import("./components/SyncOnboarding"));
const RecoverPlayer = lazy(() => import("~/renderer/screens/recover/Player"));
const NFTGallery = lazy(() => import("~/renderer/screens/nft/Gallery"));
+const NFTGalleryNew = lazy(() => import("LLD/features/Collectibles/Nfts/screens/Gallery"));
const NFTCollection = lazy(() => import("~/renderer/screens/nft/Gallery/Collection"));
+const NFTCollectionNew = lazy(() => import("LLD/features/Collectibles/Nfts/screens/Collection"));
const RecoverRestore = lazy(() => import("~/renderer/components/RecoverRestore"));
const Onboarding = lazy(() => import("~/renderer/components/Onboarding"));
const PostOnboardingScreen = lazy(() => import("~/renderer/components/PostOnboardingScreen"));
@@ -200,9 +202,10 @@ export default function Default() {
const analyticsFF = useFeature("lldAnalyticsOptInPrompt");
const hasSeenAnalyticsOptInPrompt = useSelector(hasSeenAnalyticsOptInPromptSelector);
+ const nftReworked = useFeature("lldNftsGalleryNewArch");
const isLocked = useSelector(isLockedSelector);
const dispatch = useDispatch();
-
+ const isNftReworkedEnabled = nftReworked?.enabled;
useEffect(() => {
if (
!isLocked &&
@@ -343,12 +346,16 @@ export default function Default() {
diff --git a/apps/ledger-live-desktop/src/renderer/actions/accounts.ts b/apps/ledger-live-desktop/src/renderer/actions/accounts.ts
index ca53f82c2e93..cbf7c69a4713 100644
--- a/apps/ledger-live-desktop/src/renderer/actions/accounts.ts
+++ b/apps/ledger-live-desktop/src/renderer/actions/accounts.ts
@@ -3,6 +3,7 @@ import { Account, AccountUserData } from "@ledgerhq/types-live";
import { AccountComparator } from "@ledgerhq/live-wallet/ordering";
import { getKey } from "~/renderer/storage";
import { PasswordIncorrectError } from "@ledgerhq/errors";
+import { getDefaultAccountName } from "@ledgerhq/live-wallet/accountName";
export const removeAccount = (payload: Account) => ({
type: "DB:REMOVE_ACCOUNT",
@@ -10,8 +11,10 @@ export const removeAccount = (payload: Account) => ({
});
export const initAccounts = (data: [Account, AccountUserData][]) => {
- const accounts = data.map(data => data[0]);
- const accountsUserData = data.map(data => data[1]);
+ const accounts = data.map(([account]) => account);
+ const accountsUserData = data
+ .filter(([account, userData]) => userData.name !== getDefaultAccountName(account))
+ .map(([, userData]) => userData);
return {
type: "INIT_ACCOUNTS",
payload: {
diff --git a/apps/ledger-live-desktop/src/renderer/actions/settings.ts b/apps/ledger-live-desktop/src/renderer/actions/settings.ts
index 8b9866162130..295ed3e70c08 100644
--- a/apps/ledger-live-desktop/src/renderer/actions/settings.ts
+++ b/apps/ledger-live-desktop/src/renderer/actions/settings.ts
@@ -100,6 +100,7 @@ export const setAllowExperimentalApps = (allowExperimentalApps: boolean) =>
saveSettings({
allowExperimentalApps,
});
+
export const setEnablePlatformDevTools = (enablePlatformDevTools: boolean) =>
saveSettings({
enablePlatformDevTools,
diff --git a/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts b/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts
index 70d274509d8b..6c857dc5e9f6 100644
--- a/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts
+++ b/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts
@@ -1,7 +1,7 @@
import { TrustchainMember } from "@ledgerhq/trustchain/types";
-import { Flow, Step } from "../reducers/walletSync";
+import { ChangeFlowPayload } from "../reducers/walletSync";
-export const setFlow = (payload: { flow: Flow; step: Step }) => ({
+export const setFlow = (payload: ChangeFlowPayload) => ({
type: "WALLET_SYNC_CHANGE_FLOW",
payload,
});
diff --git a/apps/ledger-live-desktop/src/renderer/analytics/segment.ts b/apps/ledger-live-desktop/src/renderer/analytics/segment.ts
index 0fa152742462..4aff4b9b914d 100644
--- a/apps/ledger-live-desktop/src/renderer/analytics/segment.ts
+++ b/apps/ledger-live-desktop/src/renderer/analytics/segment.ts
@@ -67,13 +67,13 @@ const getMarketWidgetAnalytics = () => {
return !!marketWidget?.enabled;
};
-const getWalletSyncAttributes = (state: State) => {
+const getLedgerSyncAttributes = (state: State) => {
if (!analyticsFeatureFlagMethod) return false;
const walletSync = analyticsFeatureFlagMethod("lldWalletSync");
return {
- hasWalletSync: !!walletSync?.enabled,
- walletSyncActivated: !!state.trustchain.trustchain,
+ hasLedgerSync: !!walletSync?.enabled,
+ ledgerSyncActivated: !!state.trustchain.trustchain?.rootId,
};
};
@@ -81,10 +81,12 @@ const getPtxAttributes = () => {
if (!analyticsFeatureFlagMethod) return {};
const fetchAdditionalCoins = analyticsFeatureFlagMethod("fetchAdditionalCoins");
const stakingProviders = analyticsFeatureFlagMethod("ethStakingProviders");
+ const ptxCard = analyticsFeatureFlagMethod("ptxCard");
const ptxSwapMoonpayProviderFlag = analyticsFeatureFlagMethod("ptxSwapMoonpayProvider");
const ptxSwapLiveAppDemoZero = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoZero")?.enabled;
const ptxSwapLiveAppDemoOne = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoOne")?.enabled;
+ const ptxSwapLiveAppDemoThree = analyticsFeatureFlagMethod("ptxSwapLiveAppDemoThree")?.enabled;
const ptxSwapThorswapProvider = analyticsFeatureFlagMethod("ptxSwapThorswapProvider")?.enabled;
const ptxSwapExodusProvider = analyticsFeatureFlagMethod("ptxSwapExodusProvider")?.enabled;
@@ -106,9 +108,11 @@ const getPtxAttributes = () => {
isBatch2Enabled,
isBatch3Enabled,
stakingProvidersEnabled,
+ ptxCard,
ptxSwapMoonpayProviderEnabled,
ptxSwapLiveAppDemoZero,
ptxSwapLiveAppDemoOne,
+ ptxSwapLiveAppDemoThree,
ptxSwapThorswapProvider,
ptxSwapExodusProvider,
};
@@ -140,7 +144,7 @@ const extraProperties = (store: ReduxStore) => {
const accounts = accountsSelector(state);
const ptxAttributes = getPtxAttributes();
- const walletSyncAtributes = getWalletSyncAttributes(state);
+ const ledgerSyncAtributes = getLedgerSyncAttributes(state);
const deviceInfo = device
? {
@@ -195,7 +199,7 @@ const extraProperties = (store: ReduxStore) => {
modelIdList: devices,
...ptxAttributes,
...deviceInfo,
- ...walletSyncAtributes,
+ ...ledgerSyncAtributes,
};
};
@@ -295,8 +299,8 @@ export const track = (
}
const eventPropertiesWithoutExtra = {
- ...properties,
page: currentRouteNameRef.current,
+ ...properties,
};
const allProperties = {
diff --git a/apps/ledger-live-desktop/src/renderer/components/CustomImage/ImportImage.tsx b/apps/ledger-live-desktop/src/renderer/components/CustomImage/ImportImage.tsx
index 3ccc4450b7a1..05c902f88ada 100644
--- a/apps/ledger-live-desktop/src/renderer/components/CustomImage/ImportImage.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/CustomImage/ImportImage.tsx
@@ -16,9 +16,19 @@ type Props = {
onClick: () => void;
};
+const acceptedMimeTypes = [
+ "image/jpeg",
+ "image/png",
+ "image/bmp",
+ "image/tiff",
+ "image/heif",
+ "image/heic",
+];
+const acceptedMimeTypesString = acceptedMimeTypes.join(", ");
+
const ImageInput = styled.input.attrs({
type: "file",
- accept: "image/*",
+ accept: acceptedMimeTypesString,
title: "",
value: "",
})`
@@ -40,7 +50,7 @@ const ImportImage: React.FC = ({ setLoading, onResult, onError, onClick }
try {
const reader = new FileReader();
if (!file) return;
- if (!file.type.startsWith("image/")) {
+ if (!acceptedMimeTypes.includes(file.type)) {
onError(new ImageIncorrectFileTypeError());
return;
}
diff --git a/apps/ledger-live-desktop/src/renderer/components/ExportOperationsBtn.tsx b/apps/ledger-live-desktop/src/renderer/components/ExportOperationsBtn.tsx
index 7bece556ae7d..cc6db41c75a8 100644
--- a/apps/ledger-live-desktop/src/renderer/components/ExportOperationsBtn.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/ExportOperationsBtn.tsx
@@ -18,6 +18,7 @@ type Props = {
openModal: (b: string) => void;
primary?: boolean;
accounts: Account[];
+ dataTestId?: string;
};
const mapDispatchToProps = {
openModal,
@@ -28,7 +29,7 @@ const mapStateToProps = createStructuredSelector({
class ExportOperationsBtn extends Component {
openModal = () => this.props.openModal("MODAL_EXPORT_OPERATIONS");
render() {
- const { t, primary, accounts } = this.props;
+ const { t, primary, accounts, dataTestId } = this.props;
if (!accounts.length && !primary) return null;
return primary ? (
diff --git a/apps/ledger-live-desktop/src/renderer/components/LiveAppDrawer.tsx b/apps/ledger-live-desktop/src/renderer/components/LiveAppDrawer.tsx
index 34a67578068e..bb20bc94266d 100644
--- a/apps/ledger-live-desktop/src/renderer/components/LiveAppDrawer.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/LiveAppDrawer.tsx
@@ -30,6 +30,7 @@ import CompleteExchange, {
} from "~/renderer/modals/Platform/Exchange/CompleteExchange/Body";
import { ExchangeType } from "@ledgerhq/live-common/wallet-api/Exchange/server";
import { Exchange } from "@ledgerhq/live-common/exchange/types";
+import { renderLoading } from "./DeviceAction/rendering";
const Divider = styled(Box)`
border: 1px solid ${p => p.theme.colors.palette.divider};
@@ -61,6 +62,9 @@ export function isStartExchangeData(data: unknown): data is StartExchangeData {
export const LiveAppDrawer = () => {
const [dismissDisclaimerChecked, setDismissDisclaimerChecked] = useState(false);
+ const { t } = useTranslation();
+ const dispatch = useDispatch();
+
// @ts-expect-error how to type payload?
const {
isOpen,
@@ -77,8 +81,6 @@ export const LiveAppDrawer = () => {
};
} = useSelector(platformAppDrawerStateSelector);
- const { t } = useTranslation();
- const dispatch = useDispatch();
const onContinue = useCallback(() => {
if (payload && payload.type === "DAPP_DISCLAIMER") {
const { manifest, disclaimerId, next } = payload;
@@ -89,11 +91,14 @@ export const LiveAppDrawer = () => {
next(manifest, dismissDisclaimerChecked);
}
}, [dismissDisclaimerChecked, dispatch, payload]);
+
const drawerContent = useMemo(() => {
if (!payload) {
return null;
}
+
const { type, manifest, data } = payload;
+
const action = createAction(connectApp, startExchange);
switch (type) {
case "DAPP_INFO":
@@ -156,6 +161,7 @@ export const LiveAppDrawer = () => {
renderLoading()}
onResult={result => {
if ("startExchangeResult" in result) {
data.onResult(result.startExchangeResult);
diff --git a/apps/ledger-live-desktop/src/renderer/components/MainSideBar/index.tsx b/apps/ledger-live-desktop/src/renderer/components/MainSideBar/index.tsx
index dc96f936321e..b7501f8ef18d 100644
--- a/apps/ledger-live-desktop/src/renderer/components/MainSideBar/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/MainSideBar/index.tsx
@@ -30,7 +30,7 @@ import UpdateDot from "~/renderer/components/Updater/UpdateDot";
import { Dot } from "~/renderer/components/Dot";
import Stars from "~/renderer/components/Stars";
import useEnv from "@ledgerhq/live-common/hooks/useEnv";
-import { CARD_APP_ID } from "~/renderer/screens/card";
+import { BAANX_APP_ID } from "~/renderer/screens/card/CardPlatformApp";
import TopGradient from "./TopGradient";
import Hide from "./Hide";
import { track } from "~/renderer/analytics/segment";
@@ -223,7 +223,7 @@ const MainSideBar = () => {
const location = useLocation();
const dispatch = useDispatch();
const { t } = useTranslation();
- const manifest = useRemoteLiveAppManifest(CARD_APP_ID);
+ const manifest = useRemoteLiveAppManifest(BAANX_APP_ID);
const isCardDisabled = !manifest;
/** redux navigation locked state */
diff --git a/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/SelectUseCase/index.tsx b/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/SelectUseCase/index.tsx
index 0d076536c327..471f0770d5e0 100644
--- a/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/SelectUseCase/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/SelectUseCase/index.tsx
@@ -206,14 +206,11 @@ export function SelectUseCase({ setUseCase, setOpenedPedagogyModal }: Props) {
onClick={() => {
track("Onboarding - Restore With Recover");
- if (
- deviceModelId &&
- [DeviceModelId.nanoX, DeviceModelId.stax].includes(deviceModelId)
- ) {
+ if (deviceModelId === DeviceModelId.nanoS) {
+ dispatch(openModal("MODAL_PROTECT_DISCOVER", undefined));
+ } else {
setUseCase(UseCase.recover);
history.push(`/onboarding/${UseCase.recover}/${ScreenId.pairMyNano}`);
- } else {
- dispatch(openModal("MODAL_PROTECT_DISCOVER", undefined));
}
}}
/>
diff --git a/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/Welcome/index.tsx b/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/Welcome/index.tsx
index 241f2cf602cb..a0a21a35c5a2 100644
--- a/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/Welcome/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/Onboarding/Screens/Welcome/index.tsx
@@ -146,7 +146,7 @@ export function Welcome() {
const {
analyticsOptInPromptProps,
isFeatureFlagsAnalyticsPrefDisplayed,
- openAnalitycsOptInPrompt,
+ openAnalyticsOptInPrompt,
onSubmit,
} = useAnalyticsOptInPrompt({
entryPoint: EntryPoint.onboarding,
@@ -182,7 +182,7 @@ export function Welcome() {
variant="main"
onClick={_ => {
isFeatureFlagsAnalyticsPrefDisplayed
- ? openAnalitycsOptInPrompt("Onboarding", handleAcceptTermsAndGetStarted)
+ ? openAnalyticsOptInPrompt("Onboarding", handleAcceptTermsAndGetStarted)
: handleAcceptTermsAndGetStarted();
}}
mb="5"
@@ -194,7 +194,7 @@ export function Welcome() {
variant="main"
onClick={_ => {
isFeatureFlagsAnalyticsPrefDisplayed
- ? openAnalitycsOptInPrompt("Onboarding", buyNanoX)
+ ? openAnalyticsOptInPrompt("Onboarding", buyNanoX)
: buyNanoX();
}}
outline={true}
diff --git a/apps/ledger-live-desktop/src/renderer/components/TopBar/ActivityIndicator.tsx b/apps/ledger-live-desktop/src/renderer/components/TopBar/ActivityIndicator.tsx
index e6631040a40d..ca9c3be61b6a 100644
--- a/apps/ledger-live-desktop/src/renderer/components/TopBar/ActivityIndicator.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/TopBar/ActivityIndicator.tsx
@@ -14,7 +14,7 @@ import Tooltip from "../Tooltip";
import TranslatedError from "../TranslatedError";
import Box from "../Box";
import { ItemContainer } from "./shared";
-import { useWalletSyncUserState } from "~/newArch/features/WalletSync/components/WalletSyncContext";
+import { useWalletSyncUserState } from "LLD/features/WalletSync/components/WalletSyncContext";
export default function ActivityIndicatorInner() {
const wsUserState = useWalletSyncUserState();
diff --git a/apps/ledger-live-desktop/src/renderer/components/TopBar/index.tsx b/apps/ledger-live-desktop/src/renderer/components/TopBar/index.tsx
index 150f67d5040a..1c4b6948cbac 100644
--- a/apps/ledger-live-desktop/src/renderer/components/TopBar/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/TopBar/index.tsx
@@ -11,6 +11,8 @@ import Box from "~/renderer/components/Box";
import Tooltip from "~/renderer/components/Tooltip";
import Breadcrumb from "~/renderer/components/Breadcrumb";
import HelpSideBar from "~/renderer/modals/Help";
+import BreadCrumbNewArch from "LLD/components/BreadCrumb";
+import { useFeature } from "@ledgerhq/live-common/featureFlags/index";
// TODO: ActivityIndicator
import ActivityIndicator from "./ActivityIndicator";
@@ -49,6 +51,8 @@ const TopBar = () => {
const hasPassword = useSelector(hasPasswordSelector);
const hasAccounts = useSelector(hasAccountsSelector);
const discreetMode = useSelector(discreetModeSelector);
+ const nftReworked = useFeature("lldNftsGalleryNewArch");
+ const isNftReworkedEnabled = nftReworked?.enabled;
const [helpSideBarVisible, setHelpSideBarVisible] = useState(false);
const handleLock = useCallback(() => dispatch(lock()), [dispatch]);
const handleDiscreet = useCallback(
@@ -68,7 +72,7 @@ const TopBar = () => {
-
+ {isNftReworkedEnabled ? : }
{hasAccounts && (
<>
diff --git a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx
index aa86f51b2546..c1237d6124bb 100644
--- a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx
@@ -121,6 +121,7 @@ function useUiHook(manifest: AppManifest, tracking: Record {
setDrawer(
@@ -297,5 +297,5 @@ export function useSelectAccount({
);
}, [currencies, manifest.id, setCurrentAccountHist]);
- return { onSelectAccount };
+ return { onSelectAccount, currentAccount };
}
diff --git a/apps/ledger-live-desktop/src/renderer/components/WebPTXPlayer/TopBar.tsx b/apps/ledger-live-desktop/src/renderer/components/WebPTXPlayer/TopBar.tsx
index 9fa2d1120e1b..e05907d83484 100644
--- a/apps/ledger-live-desktop/src/renderer/components/WebPTXPlayer/TopBar.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/WebPTXPlayer/TopBar.tsx
@@ -1,6 +1,6 @@
import React, { RefObject, useCallback, useEffect, useMemo, useRef } from "react";
import { useHistory, useRouteMatch } from "react-router";
-import { Trans } from "react-i18next";
+import { Trans, useTranslation } from "react-i18next";
import styled from "styled-components";
import { LiveAppManifest } from "@ledgerhq/live-common/platform/types";
import { rgba } from "~/renderer/styles/helpers";
@@ -101,6 +101,7 @@ export type Props = {
};
export const TopBar = ({ manifest, webviewAPIRef, webviewState }: Props) => {
+ const { t } = useTranslation();
const lastMatchingURL = useRef(null);
const history = useHistory();
const match = useRouteMatch();
@@ -171,8 +172,8 @@ export const TopBar = ({ manifest, webviewAPIRef, webviewState }: Props) => {
const getButtonLabel = useCallback(() => {
const lastScreen = localStorage.getItem("last-screen") || "";
- return lastScreen === "compare_providers" ? "Quote" : manifest.name;
- }, [localStorage, manifest]);
+ return lastScreen === "compare_providers" ? t("common.quote") : manifest.name;
+ }, [localStorage, manifest, t]);
const handleReload = useCallback(() => {
const webview = safeGetRefValue(webviewAPIRef);
diff --git a/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/TopBar.tsx b/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/TopBar.tsx
index 7ceca9c27183..9d3503011dff 100644
--- a/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/TopBar.tsx
+++ b/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/TopBar.tsx
@@ -18,7 +18,6 @@ import { WebviewAPI, WebviewState } from "../Web3AppWebview/types";
import Spinner from "../Spinner";
import { getAccountCurrency } from "@ledgerhq/live-common/account/helpers";
import { useDebounce } from "@ledgerhq/live-common/hooks/useDebounce";
-import { useDappCurrentAccount } from "@ledgerhq/live-common/wallet-api/useDappLogic";
import { CurrentAccountHistDB, safeGetRefValue } from "@ledgerhq/live-common/wallet-api/react";
import Wallet from "~/renderer/icons/Wallet";
import { getDefaultAccountName } from "@ledgerhq/live-wallet/accountName";
@@ -142,7 +141,6 @@ export const TopBar = ({
webviewState,
}: Props) => {
const { name, icon } = manifest;
- const { currentAccount } = useDappCurrentAccount(currentAccountHistDb);
const {
shouldDisplayName = true,
@@ -183,7 +181,7 @@ export const TopBar = ({
webview.goForward();
}, [webviewAPIRef]);
- const { onSelectAccount } = useSelectAccount({ manifest, currentAccountHistDb });
+ const { onSelectAccount, currentAccount } = useSelectAccount({ manifest, currentAccountHistDb });
const isLoading = useDebounce(webviewState.loading, 100);
diff --git a/apps/ledger-live-desktop/src/renderer/drawers/OperationDetails/index.tsx b/apps/ledger-live-desktop/src/renderer/drawers/OperationDetails/index.tsx
index bcbf19ce9517..ea7c3f7f7a00 100644
--- a/apps/ledger-live-desktop/src/renderer/drawers/OperationDetails/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/drawers/OperationDetails/index.tsx
@@ -358,6 +358,7 @@ const OperationD = (props: Props) => {
showCode
val={amount}
fontSize={7}
+ data-testid="amountReceived-drawer"
disableRounding
/>
diff --git a/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx b/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx
index f7992002a077..3b684e45b92f 100644
--- a/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx
@@ -11,18 +11,10 @@ import SelectFeeStrategy, { OnClickType } from "~/renderer/components/SelectFeeS
import SendFeeMode from "~/renderer/components/SendFeeMode";
import Text from "~/renderer/components/Text";
import Tooltip from "~/renderer/components/Tooltip";
-import { context } from "~/renderer/drawers/Provider";
import CoinControlModal from "./CoinControlModal";
import { FeesField } from "./FeesField";
import { BitcoinFamily } from "./types";
import useBitcoinPickingStrategy from "./useBitcoinPickingStrategy";
-import Alert from "~/renderer/components/Alert";
-import TranslatedError from "~/renderer/components/TranslatedError";
-import { useDispatch } from "react-redux";
-import { useHistory } from "react-router";
-import { closeAllModal } from "~/renderer/actions/modals";
-import { setTrackingSource } from "~/renderer/analytics/TrackPage";
-import { Flex } from "@ledgerhq/react-ui";
type Props = NonNullable["component"];
@@ -44,33 +36,16 @@ const Fields: Props = ({
}) => {
const bridge = getAccountBridge(account);
const { t } = useTranslation();
- const { state: drawerState, setDrawer } = React.useContext(context);
const [coinControlOpened, setCoinControlOpened] = useState(false);
- const [isAdvanceMode, setAdvanceMode] = useState(!transaction.feesStrategy);
+ const [isAdvanceMode, setAdvanceMode] = useState(
+ !transaction.feesStrategy || transaction.feesStrategy === "custom",
+ );
const strategies = useFeesStrategy(account, transaction);
const onCoinControlOpen = useCallback(() => setCoinControlOpened(true), []);
const onCoinControlClose = useCallback(() => setCoinControlOpened(false), []);
const { item } = useBitcoinPickingStrategy(transaction.utxoStrategy.strategy);
const canNext = account.bitcoinResources?.utxos?.length;
- const dispatch = useDispatch();
- const history = useHistory();
-
- const onBuyClick = useCallback(() => {
- dispatch(closeAllModal());
- setTrackingSource("send flow");
- history.push({
- pathname: "/exchange",
- state: {
- currency: account.currency.id,
- account: account.id,
- mode: "buy", // buy or sell
- },
- });
- }, [account.currency.id, account.id, dispatch, history]);
-
- const { errors } = status;
- const { gasPrice: messageGas } = errors;
/* TODO: How do we set default RBF to be true ? (@gre)
* Meanwhile, using this trick (please don't kill me)
*/
@@ -95,7 +70,6 @@ const Fields: Props = ({
feesStrategy,
}),
);
- if (drawerState.open) setDrawer(undefined);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[updateTransaction, bridge],
@@ -183,13 +157,6 @@ const Fields: Props = ({
mapStrategies={mapStrategies}
status={status}
/>
- {messageGas && (
-
-
-
-
-
- )}
>
)}
>
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/AccountBalanceSummaryFooter.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/AccountBalanceSummaryFooter.tsx
index 9ed31856141b..253aa460eca2 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/AccountBalanceSummaryFooter.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/AccountBalanceSummaryFooter.tsx
@@ -12,7 +12,7 @@ import Text from "~/renderer/components/Text";
import InfoCircle from "~/renderer/icons/InfoCircle";
import ToolTip from "~/renderer/components/Tooltip";
import { CosmosAccount } from "@ledgerhq/live-common/families/cosmos/types";
-import { CosmosAPI } from "@ledgerhq/live-common/families/cosmos/api/Cosmos";
+import { CosmosAPI } from "@ledgerhq/coin-cosmos/api/Cosmos";
import { SubAccount } from "@ledgerhq/types-live";
import { useAccountUnit } from "~/renderer/hooks/useAccountUnit";
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx
index 16dddd1dbdca..0e035da2ddc7 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx
@@ -23,7 +23,7 @@ import StepClaimRewards, { StepClaimRewardsFooter } from "./steps/StepClaimRewar
import GenericStepConnectDevice from "~/renderer/modals/Send/steps/GenericStepConnectDevice";
import StepConfirmation, { StepConfirmationFooter } from "./steps/StepConfirmation";
import logger from "~/renderer/logger";
-import { CosmosAccount } from "@ledgerhq/live-common/families/cosmos/types";
+import type { CosmosAccount } from "@ledgerhq/coin-cosmos/types/index";
export type Data = {
account: CosmosAccount;
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx
index 5457f858c9f2..c40af92b4203 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx
@@ -5,7 +5,7 @@ import ToggleButton from "~/renderer/components/ToggleButton";
import InfoCircle from "~/renderer/icons/InfoCircle";
import Text from "~/renderer/components/Text";
import Popover from "~/renderer/components/Popover";
-import { CosmosLikeTransaction } from "@ledgerhq/live-common/families/cosmos/types";
+import type { CosmosLikeTransaction } from "@ledgerhq/coin-cosmos/types/index";
const options = [
{
value: "claimRewardCompound",
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx
index fdfe7d5c172c..710332ecef5e 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx
@@ -14,10 +14,11 @@ import Text from "~/renderer/components/Text";
import DelegationSelectorField from "../fields/DelegationSelectorField";
import ErrorBanner from "~/renderer/components/ErrorBanner";
import AccountFooter from "~/renderer/modals/Send/AccountFooter";
-import {
+import type {
CosmosLikeTransaction,
CosmosMappedDelegation,
-} from "@ledgerhq/live-common/families/cosmos/types";
+} from "@ledgerhq/coin-cosmos/types/index";
+
import { useAccountUnit } from "~/renderer/hooks/useAccountUnit";
export default function StepClaimRewards({
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/types.ts b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/types.ts
index d7edc05242f1..64c26984b85d 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/types.ts
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/types.ts
@@ -2,11 +2,12 @@ import { TFunction } from "i18next";
import { Device } from "@ledgerhq/live-common/hw/actions/types";
import { Step } from "~/renderer/components/Stepper";
import { Operation } from "@ledgerhq/types-live";
-import {
+import type {
CosmosAccount,
Transaction,
TransactionStatus,
-} from "@ledgerhq/live-common/families/cosmos/types";
+} from "@ledgerhq/coin-cosmos/types/index";
+
import { OpenModal } from "~/renderer/actions/modals";
export type StepId = "claimRewards" | "connectDevice" | "confirmation";
export type StepProps = {
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/index.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/index.tsx
index df155112a242..35f6c9e442f5 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/index.tsx
@@ -19,16 +19,16 @@ import LinkWithExternalIcon from "~/renderer/components/LinkWithExternalIcon";
import IconChartLine from "~/renderer/icons/ChartLine";
import { Header, UnbondingHeader } from "./Header";
import { Row, UnbondingRow } from "./Row";
-import cosmosBase from "@ledgerhq/live-common/families/cosmos/chain/cosmosBase";
import ToolTip from "~/renderer/components/Tooltip";
import ClaimRewards from "~/renderer/icons/ClaimReward";
import DelegateIcon from "~/renderer/icons/Delegate";
import TableContainer, { TableHeader } from "~/renderer/components/TableContainer";
import { CosmosAccount } from "@ledgerhq/live-common/families/cosmos/types";
import { DelegationActionsModalName } from "../modals";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { useLocalizedUrl } from "~/renderer/hooks/useLocalizedUrls";
import { useAccountUnit } from "~/renderer/hooks/useAccountUnit";
+import cosmosBase from "@ledgerhq/coin-cosmos/chain/cosmosBase";
const Wrapper = styled(Box).attrs(() => ({
p: 3,
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx
index 178382230082..3c552904ba29 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx
@@ -19,7 +19,7 @@ import { getCurrentDevice } from "~/renderer/reducers/devices";
import { OpenModal, openModal } from "~/renderer/actions/modals";
import StepAmount, { StepAmountFooter } from "./steps/StepAmount";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { BigNumber } from "bignumber.js";
import Stepper from "~/renderer/components/Stepper";
import StepDelegation, { StepDelegationFooter } from "./steps/StepDelegation";
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Info/index.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Info/index.tsx
index 6cdbf7b38d2a..05d8f927d02c 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Info/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Info/index.tsx
@@ -6,7 +6,7 @@ import EarnRewardsInfoModal from "~/renderer/components/EarnRewardsInfoModal";
import WarnBox from "~/renderer/components/WarnBox";
import { openURL } from "~/renderer/linking";
import LinkWithExternalIcon from "~/renderer/components/LinkWithExternalIcon";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { CosmosAccount } from "@ledgerhq/live-common/families/cosmos/types";
export type Props = {
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepStarter.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepStarter.tsx
index 07e634afda50..5a5f18a01662 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepStarter.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepStarter.tsx
@@ -11,7 +11,7 @@ import Rewards from "~/renderer/images/rewards.svg";
import Alert from "~/renderer/components/Alert";
import LinkWithExternalIcon from "~/renderer/components/LinkWithExternalIcon";
import { openURL } from "~/renderer/linking";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { urls } from "~/config/urls";
import { useLocalizedUrl } from "~/renderer/hooks/useLocalizedUrls";
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx
index 042a42f9ff5e..c59063eff92b 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx
@@ -19,7 +19,7 @@ import ChevronRight from "~/renderer/icons/ChevronRightSmall";
import CosmosFamilyLedgerValidatorIcon from "~/renderer/families/cosmos/shared/components/CosmosFamilyLedgerValidatorIcon";
import Text from "~/renderer/components/Text";
import AccountFooter from "~/renderer/modals/Send/AccountFooter";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { CosmosMappedDelegation } from "@ledgerhq/live-common/families/cosmos/types";
const SelectButton = styled(Base)`
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/TransactionConfirmFields.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/TransactionConfirmFields.tsx
index 03d5a7adbd4a..c679388ec7b4 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/TransactionConfirmFields.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/TransactionConfirmFields.tsx
@@ -73,7 +73,7 @@ export const CosmosDelegateValidatorsField = ({
const { validators } = transaction;
const currencyId = mainAccount.currency.id;
const { validators: cosmosValidators } = useCosmosFamilyPreloadData(currencyId);
- const mappedValidators = mapDelegationInfo(validators || [], cosmosValidators, unit);
+ const mappedValidators = mapDelegationInfo(validators || [], cosmosValidators, unit, transaction);
return mappedValidators && mappedValidators.length > 0 ? (
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx
index 6e8bb353af0c..2fd54cbf57d1 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx
@@ -16,7 +16,7 @@ import Text from "~/renderer/components/Text";
import Alert from "~/renderer/components/Alert";
import ErrorBanner from "~/renderer/components/ErrorBanner";
import AccountFooter from "~/renderer/modals/Send/AccountFooter";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
export default function StepAmount({
account,
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/operationDetails.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/operationDetails.tsx
index 5eb6c205eb63..8b6c7079fe68 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/operationDetails.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/operationDetails.tsx
@@ -2,7 +2,7 @@
import { getAccountCurrency } from "@ledgerhq/live-common/account/index";
import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index";
import { getAddressExplorer, getDefaultExplorerView } from "@ledgerhq/live-common/explorers";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { mapDelegationInfo } from "@ledgerhq/live-common/families/cosmos/logic";
import { useCosmosFamilyPreloadData } from "@ledgerhq/live-common/families/cosmos/react";
import {
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyLedgerValidatorIcon.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyLedgerValidatorIcon.tsx
index abc61dbd8125..ed73634b3889 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyLedgerValidatorIcon.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyLedgerValidatorIcon.tsx
@@ -1,10 +1,11 @@
import { CosmosValidatorItem } from "@ledgerhq/live-common/families/cosmos/types";
import React from "react";
-import cosmosBase from "@ledgerhq/live-common/families/cosmos/chain/cosmosBase";
+import cosmosBase from "@ledgerhq/coin-cosmos/chain/cosmosBase";
import { IconContainer } from "~/renderer/components/Delegation/ValidatorRow";
import LedgerLiveLogo from "~/renderer/components/LedgerLiveLogo";
import Logo from "~/renderer/icons/Logo";
import FirstLetterIcon from "~/renderer/components/FirstLetterIcon";
+
const CosmosFamilyLedgerValidatorIcon = ({
validator,
}: {
diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyValidatorRow.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyValidatorRow.tsx
index f817b0f8ef33..22597bcdb259 100644
--- a/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyValidatorRow.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/shared/components/CosmosFamilyValidatorRow.tsx
@@ -1,6 +1,6 @@
import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index";
import { getDefaultExplorerView, getAddressExplorer } from "@ledgerhq/live-common/explorers";
-import cryptoFactory from "@ledgerhq/live-common/families/cosmos/chain/chain";
+import cryptoFactory from "@ledgerhq/coin-cosmos/chain/chain";
import { CosmosValidatorItem } from "@ledgerhq/live-common/families/cosmos/types";
import { CryptoCurrency, Unit } from "@ledgerhq/types-cryptoassets";
import { BigNumber } from "bignumber.js";
diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx
index f750ec718502..bfb477d60c0f 100644
--- a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx
@@ -25,8 +25,7 @@ const Root: NonNullable["component"] = props => {
const bridge: AccountBridge = getAccountBridge(account);
const { errors } = props.status;
- const { gasPrice: messageGas } = errors;
-
+ const { gasPrice: messageGas, amount: messageAmount } = errors;
const dispatch = useDispatch();
const history = useHistory();
@@ -112,10 +111,10 @@ const Root: NonNullable["component"] = props => {
>
)}
- {messageGas && (
+ {(messageGas || messageAmount) && (
-
-
+
+
)}
diff --git a/apps/ledger-live-desktop/src/renderer/families/filecoin/TransactionConfirmFields.tsx b/apps/ledger-live-desktop/src/renderer/families/filecoin/TransactionConfirmFields.tsx
index eea43bbd8124..c97bb00d58b1 100644
--- a/apps/ledger-live-desktop/src/renderer/families/filecoin/TransactionConfirmFields.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/filecoin/TransactionConfirmFields.tsx
@@ -26,6 +26,7 @@ const fieldComponents = {
"filecoin.gasPremium": FilecoinField,
"filecoin.gasLimit": FilecoinField,
"filecoin.method": FilecoinField,
+ "filecoin.recipient": FilecoinField,
};
export default {
fieldComponents,
diff --git a/apps/ledger-live-desktop/src/renderer/families/ton/CommentField.tsx b/apps/ledger-live-desktop/src/renderer/families/ton/CommentField.tsx
index 154434ffa97e..09a302497386 100644
--- a/apps/ledger-live-desktop/src/renderer/families/ton/CommentField.tsx
+++ b/apps/ledger-live-desktop/src/renderer/families/ton/CommentField.tsx
@@ -38,7 +38,7 @@ const CommentField = ({
// on the ledger-live mobile
return (
-
-
+
+
diff --git a/apps/ledger-live-desktop/src/renderer/DesktopStorageProvider.ts b/apps/ledger-live-desktop/src/renderer/hooks/storage-provider/DesktopAppDataStorageProvider.ts
similarity index 94%
rename from apps/ledger-live-desktop/src/renderer/DesktopStorageProvider.ts
rename to apps/ledger-live-desktop/src/renderer/hooks/storage-provider/DesktopAppDataStorageProvider.ts
index 2393ede2515e..042c16d79c5d 100644
--- a/apps/ledger-live-desktop/src/renderer/DesktopStorageProvider.ts
+++ b/apps/ledger-live-desktop/src/renderer/hooks/storage-provider/DesktopAppDataStorageProvider.ts
@@ -1,5 +1,5 @@
import {
- StorageProvider,
+ StorageProvider as AppDataStorageProvider,
AppStorageType,
AppStorageKey,
isAppStorageType,
@@ -10,7 +10,7 @@ import {
* The storage provider for LLD that implements the StorageProvider interface.
* This a temporary placement for the DesktopStorageProvider, it could be moved to the appropriate location if needed.
*/
-export class DesktopStorageProvider implements StorageProvider {
+export class DesktopAppDataStorageProvider implements AppDataStorageProvider {
/**
* Retrieves the value associated with the specified key from the storage.
*
diff --git a/apps/ledger-live-desktop/src/renderer/hooks/storage-provider/useAppDataStorage.tsx b/apps/ledger-live-desktop/src/renderer/hooks/storage-provider/useAppDataStorage.tsx
new file mode 100644
index 000000000000..e1a70a6df3d4
--- /dev/null
+++ b/apps/ledger-live-desktop/src/renderer/hooks/storage-provider/useAppDataStorage.tsx
@@ -0,0 +1,19 @@
+import React, { createContext, useContext } from "react";
+import { DesktopAppDataStorageProvider } from "./DesktopAppDataStorageProvider";
+
+const AppDataStorageContext = createContext(new DesktopAppDataStorageProvider());
+
+export const useAppDataStorageProvider = () => {
+ return useContext(AppDataStorageContext);
+};
+
+type Props = {
+ children: React.ReactNode;
+};
+
+export function AppDataStorageProvider({ children }: Props) {
+ const storage = useAppDataStorageProvider();
+ return (
+ {children}
+ );
+}
diff --git a/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts b/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts
index 5e98962531f6..0834195f8231 100644
--- a/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts
+++ b/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts
@@ -18,6 +18,7 @@ import { Account, SubAccount } from "@ledgerhq/types-live";
import { useStorylyContext } from "~/storyly/StorylyProvider";
import { useNavigateToPostOnboardingHubCallback } from "~/renderer/components/PostOnboardingHub/logic/useNavigateToPostOnboardingHubCallback";
import { usePostOnboardingDeeplinkHandler } from "@ledgerhq/live-common/postOnboarding/hooks/index";
+import { setDrawerVisibility as setLedgerSyncDrawerVisibility } from "../actions/walletSync";
const getAccountsOrSubAccountsByCurrency = (
currency: CryptoOrTokenCurrency,
@@ -346,6 +347,11 @@ export function useDeepLinkHandler() {
postOnboardingDeeplinkHandler(query.device);
break;
}
+ case "ledgersync": {
+ navigate("/settings/display");
+ dispatch(setLedgerSyncDrawerVisibility(true));
+ break;
+ }
case "portfolio":
default:
navigate("/");
diff --git a/apps/ledger-live-desktop/src/renderer/icons/ExternalLink.tsx b/apps/ledger-live-desktop/src/renderer/icons/ExternalLink.tsx
index 7171cf42b5be..2547d369bfc5 100644
--- a/apps/ledger-live-desktop/src/renderer/icons/ExternalLink.tsx
+++ b/apps/ledger-live-desktop/src/renderer/icons/ExternalLink.tsx
@@ -5,8 +5,8 @@ const path = (
d="M12.19 2.75H10a.75.75 0 0 1 0-1.5h4a.75.75 0 0 1 .75.75v4a.75.75 0 1 1-1.5 0V3.81L7.197 9.865a.75.75 0 0 1-1.06-1.061l6.052-6.053zm-.94 5.917a.75.75 0 1 1 1.5 0v4c0 1.15-.933 2.083-2.083 2.083H3.333a2.083 2.083 0 0 1-2.083-2.083V5.333c0-1.15.933-2.083 2.083-2.083h4a.75.75 0 1 1 0 1.5h-4a.583.583 0 0 0-.583.583v7.334c0 .322.261.583.583.583h7.334a.583.583 0 0 0 .583-.583v-4z"
/>
);
-const ExternalLink = ({ size }: { size: number }) => (
-
diff --git a/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx b/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx
index 6fa3294cc8fc..1faf8339dd05 100644
--- a/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx
+++ b/apps/ledger-live-mobile/src/screens/Portfolio/PortfolioQuickActionsBar.tsx
@@ -7,13 +7,15 @@ import { QuickActionList, type QuickActionButtonProps } from "@ledgerhq/native-u
import { TextVariants } from "@ledgerhq/native-ui/styles/theme";
import { track } from "~/analytics";
import { useRoute } from "@react-navigation/native";
+import { BaseNavigatorStackParamList } from "~/components/RootNavigator/types/BaseNavigator";
+import { EntryOf } from "~/types/helpers";
const SHARED_CONFIG = {
variant: "small" as const,
textVariant: "small" as TextVariants,
};
function PortfolioQuickActionsBar() {
- const navigation = useNavigation();
+ const navigation = useNavigation>();
const router = useRoute();
const { t } = useTranslation();
const {
@@ -21,55 +23,50 @@ function PortfolioQuickActionsBar() {
} = useQuickActions();
const onNavigate = useCallback(
- (name: string, options: object, eventButton: string) => {
+ (route: EntryOf, eventButton: string) => {
track("button_clicked", { button: eventButton, page: router.name });
- (navigation as StackNavigationProp<{ [key: string]: object | undefined }>).navigate(
- name,
- options,
- );
+ navigation.navigate(...route);
},
[navigation, router.name],
);
const quickActionsData: QuickActionButtonProps[] = [
- {
+ BUY && {
...SHARED_CONFIG,
Icon: BUY.icon,
children: t("portfolio.quickActions.buy"),
- onPress: () => onNavigate(...BUY.route, "quick_action_buy"),
+ onPress: () => onNavigate(BUY.route, "quick_action_buy"),
disabled: BUY.disabled,
},
- {
+ SWAP && {
...SHARED_CONFIG,
Icon: SWAP.icon,
children: t("portfolio.quickActions.swap"),
- onPress: () => onNavigate(...SWAP.route, "quick_action_swap"),
+ onPress: () => onNavigate(SWAP.route, "quick_action_swap"),
disabled: SWAP.disabled,
},
- {
+ SEND && {
...SHARED_CONFIG,
Icon: SEND.icon,
children: t("portfolio.quickActions.send"),
- onPress: () => onNavigate(...SEND.route, "quick_action_send"),
+ onPress: () => onNavigate(SEND.route, "quick_action_send"),
disabled: SEND.disabled,
},
- {
+ RECEIVE && {
...SHARED_CONFIG,
Icon: RECEIVE.icon,
children: t("portfolio.quickActions.deposit"),
- onPress: () => onNavigate(...RECEIVE.route, "quick_action_receive"),
+ onPress: () => onNavigate(RECEIVE.route, "quick_action_receive"),
disabled: RECEIVE.disabled,
},
- ];
- if (STAKE) {
- quickActionsData.push({
+ STAKE && {
...SHARED_CONFIG,
Icon: STAKE.icon,
children: t("portfolio.quickActions.stake"),
- onPress: () => onNavigate(...STAKE.route, "quick_action_stake"),
+ onPress: () => onNavigate(STAKE.route, "quick_action_stake"),
disabled: STAKE.disabled,
- });
- }
+ },
+ ].filter((v: T | undefined): v is T => !!v);
return ;
}
diff --git a/apps/ledger-live-mobile/src/screens/Portfolio/ReadOnly/index.tsx b/apps/ledger-live-mobile/src/screens/Portfolio/ReadOnly/index.tsx
index 9f6bbd7afc2d..621a85a99c73 100644
--- a/apps/ledger-live-mobile/src/screens/Portfolio/ReadOnly/index.tsx
+++ b/apps/ledger-live-mobile/src/screens/Portfolio/ReadOnly/index.tsx
@@ -30,7 +30,7 @@ import BuyDeviceBanner, { IMAGE_PROPS_BIG_NANO } from "~/components/BuyDeviceBan
import Assets from "../Assets";
import { AnalyticsContext } from "~/analytics/AnalyticsContext";
import { BaseComposite, StackNavigatorProps } from "~/components/RootNavigator/types/helpers";
-import FirmwareUpdateBanner from "~/newArch/features/FirmwareUpdate/components/UpdateBanner";
+import FirmwareUpdateBanner from "LLM/features/FirmwareUpdate/components/UpdateBanner";
import CollapsibleHeaderFlatList from "~/components/WalletTab/CollapsibleHeaderFlatList";
import { WalletTabNavigatorStackParamList } from "~/components/RootNavigator/types/WalletTabNavigator";
import { UpdateStep } from "../../FirmwareUpdate";
diff --git a/apps/ledger-live-mobile/src/screens/Portfolio/index.tsx b/apps/ledger-live-mobile/src/screens/Portfolio/index.tsx
index aba3472b105f..38d72b130a02 100644
--- a/apps/ledger-live-mobile/src/screens/Portfolio/index.tsx
+++ b/apps/ledger-live-mobile/src/screens/Portfolio/index.tsx
@@ -127,7 +127,6 @@ function PortfolioScreen({ navigation }: NavigationProps) {
}, [setAddModalOpened]);
const closeAddModal = useCallback(() => setAddModalOpened(false), [setAddModalOpened]);
- const reopenAddModal = useCallback(() => setAddModalOpened(true), [setAddModalOpened]);
const refreshAccountsOrdering = useRefreshAccountsOrdering();
useFocusEffect(refreshAccountsOrdering);
@@ -227,7 +226,6 @@ function PortfolioScreen({ navigation }: NavigationProps) {
diff --git a/apps/ledger-live-mobile/src/screens/RequestAccount/02-SelectAccount.tsx b/apps/ledger-live-mobile/src/screens/RequestAccount/02-SelectAccount.tsx
index c39c1cd35a60..a487fca28e61 100644
--- a/apps/ledger-live-mobile/src/screens/RequestAccount/02-SelectAccount.tsx
+++ b/apps/ledger-live-mobile/src/screens/RequestAccount/02-SelectAccount.tsx
@@ -98,11 +98,7 @@ function SelectAccount({ navigation, route }: Props) {
const { colors } = useTheme();
const { accounts$, currency, allowAddAccount, onSuccess } = route.params;
const accountIds = useGetAccountIds(accounts$);
- const accounts = useSelector(accountsByCryptoCurrencyScreenSelector(currency, accountIds)) as {
- account: AccountLike;
- subAccount: SubAccount | null;
- name: string;
- }[];
+ const accounts = useSelector(accountsByCryptoCurrencyScreenSelector(currency, accountIds));
const onSelect = useCallback(
(account: AccountLike, parentAccount?: Account) => {
onSuccess && onSuccess(account, parentAccount);
diff --git a/apps/ledger-live-mobile/src/screens/Settings/Debug/__mocks__/serviceStatus.ts b/apps/ledger-live-mobile/src/screens/Settings/Debug/__mocks__/serviceStatus.ts
index f6884278a6a2..65b39e065b9e 100644
--- a/apps/ledger-live-mobile/src/screens/Settings/Debug/__mocks__/serviceStatus.ts
+++ b/apps/ledger-live-mobile/src/screens/Settings/Debug/__mocks__/serviceStatus.ts
@@ -343,21 +343,6 @@ const statuses = {
group: false,
only_show_if_degraded: false,
},
- {
- id: "44xfftm0ztkq",
- name: "Pivx (PIVX)",
- status: "operational",
- created_at: "2020-06-22T17:55:04.800+02:00",
- updated_at: "2021-01-14T22:42:40.068+01:00",
- position: 14,
- description: null,
- showcase: true,
- start_date: null,
- group_id: "rn7ny8423ghs",
- page_id: "767c5rcj7z12",
- group: false,
- only_show_if_degraded: false,
- },
{
id: "t40n3pwhqqbq",
name: "Qtum (QTUM)",
diff --git a/apps/ledger-live-mobile/src/screens/Settings/General/WalletSyncRow.tsx b/apps/ledger-live-mobile/src/screens/Settings/General/WalletSyncRow.tsx
index c78861279a63..82af7b53a5d8 100644
--- a/apps/ledger-live-mobile/src/screens/Settings/General/WalletSyncRow.tsx
+++ b/apps/ledger-live-mobile/src/screens/Settings/General/WalletSyncRow.tsx
@@ -4,18 +4,31 @@ import { useTranslation } from "react-i18next";
import { useNavigation } from "@react-navigation/native";
import { NavigatorName, ScreenName } from "~/const";
import {
- useWalletSyncAnalytics,
+ useLedgerSyncAnalytics,
AnalyticsPage,
AnalyticsButton,
-} from "LLM/features/WalletSync/hooks/useWalletSyncAnalytics";
-import { useSelector } from "react-redux";
+} from "LLM/features/WalletSync/hooks/useLedgerSyncAnalytics";
+import { useDispatch, useSelector } from "react-redux";
import { trustchainSelector } from "@ledgerhq/trustchain/store";
+import ActivationDrawer from "LLM/features/WalletSync/screens/Activation/ActivationDrawer";
+import { Steps } from "LLM/features/WalletSync/types/Activation";
+import { activateDrawerSelector } from "~/reducers/walletSync";
+import { setLedgerSyncActivateDrawer } from "~/actions/walletSync";
+import { useCurrentStep } from "LLM/features/WalletSync/hooks/useCurrentStep";
const WalletSyncRow = () => {
const { t } = useTranslation();
- const { onClickTrack } = useWalletSyncAnalytics();
+ const { onClickTrack } = useLedgerSyncAnalytics();
const navigation = useNavigation();
+ const isDrawerVisible = useSelector(activateDrawerSelector);
+ const dispatch = useDispatch();
+ const { setCurrentStep } = useCurrentStep();
+
+ const closeDrawer = useCallback(() => {
+ dispatch(setLedgerSyncActivateDrawer(false));
+ setCurrentStep(Steps.Activation);
+ }, [dispatch, setCurrentStep]);
const trustchain = useSelector(trustchainSelector);
const navigateToWalletSyncActivationScreen = useCallback(() => {
@@ -27,21 +40,27 @@ const WalletSyncRow = () => {
screen: ScreenName.WalletSyncActivated,
});
} else {
- navigation.navigate(NavigatorName.WalletSync, {
- screen: ScreenName.WalletSyncActivationInit,
- });
+ dispatch(setLedgerSyncActivateDrawer(true));
}
- }, [navigation, onClickTrack, trustchain?.rootId]);
+ }, [navigation, onClickTrack, trustchain?.rootId, dispatch]);
return (
-
+ <>
+
+
+
+ >
);
};
diff --git a/apps/ledger-live-mobile/src/screens/SignTransaction/02-ConnectDevice.tsx b/apps/ledger-live-mobile/src/screens/SignTransaction/02-ConnectDevice.tsx
index 6d5c11e4ca08..e04ca1902850 100644
--- a/apps/ledger-live-mobile/src/screens/SignTransaction/02-ConnectDevice.tsx
+++ b/apps/ledger-live-mobile/src/screens/SignTransaction/02-ConnectDevice.tsx
@@ -5,6 +5,7 @@ import { useSelector } from "react-redux";
import { SafeAreaView } from "react-native-safe-area-context";
import { getMainAccount } from "@ledgerhq/live-common/account/index";
import useBridgeTransaction from "@ledgerhq/live-common/bridge/useBridgeTransaction";
+import { dependenciesToAppRequests } from "@ledgerhq/live-common/hw/actions/app";
import { useTheme } from "@react-navigation/native";
import { accountScreenSelector } from "~/reducers/accounts";
import DeviceAction from "~/components/DeviceAction";
@@ -27,7 +28,7 @@ function ConnectDevice({
const { colors } = useTheme();
const { account, parentAccount } = useSelector(accountScreenSelector(route));
invariant(account, "account is required");
- const { appName, onSuccess } = route.params;
+ const { appName, dependencies, onSuccess } = route.params;
const mainAccount = getMainAccount(account, parentAccount);
const { transaction, status } = useBridgeTransaction(() => ({
account: mainAccount,
@@ -46,10 +47,22 @@ function ConnectDevice({
transaction,
status,
tokenCurrency,
- dependencies: [mainAccount],
+ dependencies: [
+ { currency: mainAccount.currency },
+ ...dependenciesToAppRequests(dependencies),
+ ],
requireLatestFirmware: true,
}),
- [account, appName, mainAccount, parentAccount, status, tokenCurrency, transaction],
+ [
+ account,
+ appName,
+ dependencies,
+ mainAccount,
+ parentAccount,
+ status,
+ tokenCurrency,
+ transaction,
+ ],
);
return transaction ? (
= Omit & B;
export type PartialNullable = {
[P in keyof T]?: T[P] | null;
};
+
+export type EntryOf<
+ T extends Record,
+ K extends keyof T = keyof T,
+> = K extends unknown ? [K, T[K]] : never;
diff --git a/apps/web-tools/CHANGELOG.md b/apps/web-tools/CHANGELOG.md
index 954e1473bcd4..07dfa27cbf72 100644
--- a/apps/web-tools/CHANGELOG.md
+++ b/apps/web-tools/CHANGELOG.md
@@ -1,5 +1,75 @@
# web-tools
+## 0.9.0
+
+### Minor Changes
+
+- [#7646](https://github.com/LedgerHQ/ledger-live/pull/7646) [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added the synchronization of a trustchain from mobile to desktop by scanning the QR code
+
+- [#7777](https://github.com/LedgerHQ/ledger-live/pull/7777) [`2f7277a`](https://github.com/LedgerHQ/ledger-live/commit/2f7277a29fb2417cb5ee85d2778d86c65678a02f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update Next & react version to latest to ensure to be up to date with security fixes
+
+- [#7691](https://github.com/LedgerHQ/ledger-live/pull/7691) [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added a Loading screen on LLM and LLD when initializing ledger sync while accounts are synchronizing
+
+- [#7440](https://github.com/LedgerHQ/ledger-live/pull/7440) [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194) Thanks [@thesan](https://github.com/thesan)! - Request device access within `HWDeviceProvider`
+
+### Patch Changes
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`87c160d`](https://github.com/LedgerHQ/ledger-live/commit/87c160d855b512d5a0394eaee7626e2b8cd431ee), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`d60a022`](https://github.com/LedgerHQ/ledger-live/commit/d60a02238db9ed16142de4c1874e26d27aaaa98c), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`ef99222`](https://github.com/LedgerHQ/ledger-live/commit/ef99222a5adcd9732d06600bc875309c440e084f), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`8e0ac04`](https://github.com/LedgerHQ/ledger-live/commit/8e0ac04ac8cdaaee59633ebdf219e5dcf44a10df), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`9a732c6`](https://github.com/LedgerHQ/ledger-live/commit/9a732c6d0b6e61b39f00d46c3af240640b4883e8), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`9abf63b`](https://github.com/LedgerHQ/ledger-live/commit/9abf63b51a159fe6c501a6b50d1e33c1551834e8), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0
+ - @ledgerhq/trustchain@0.3.0
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/hw-transport-http@6.30.3
+ - @ledgerhq/hw-app-eth@6.38.1
+ - @ledgerhq/domain-service@1.2.4
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/live-wallet@0.6.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/hw-trustchain@0.1.5
+ - @ledgerhq/hw-transport@6.31.3
+ - @ledgerhq/hw-transport-web-ble@6.29.3
+ - @ledgerhq/hw-transport-webhid@6.29.3
+ - @ledgerhq/hw-transport-webusb@6.29.3
+
+## 0.9.0-next.0
+
+### Minor Changes
+
+- [#7646](https://github.com/LedgerHQ/ledger-live/pull/7646) [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added the synchronization of a trustchain from mobile to desktop by scanning the QR code
+
+- [#7777](https://github.com/LedgerHQ/ledger-live/pull/7777) [`2f7277a`](https://github.com/LedgerHQ/ledger-live/commit/2f7277a29fb2417cb5ee85d2778d86c65678a02f) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Update Next & react version to latest to ensure to be up to date with security fixes
+
+- [#7691](https://github.com/LedgerHQ/ledger-live/pull/7691) [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89) Thanks [@cgrellard-ledger](https://github.com/cgrellard-ledger)! - Ledger Sync - Added a Loading screen on LLM and LLD when initializing ledger sync while accounts are synchronizing
+
+- [#7440](https://github.com/LedgerHQ/ledger-live/pull/7440) [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194) Thanks [@thesan](https://github.com/thesan)! - Request device access within `HWDeviceProvider`
+
+### Patch Changes
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`f8756b2`](https://github.com/LedgerHQ/ledger-live/commit/f8756b29a83048d423d500e16ea3f9789763b90d), [`87c160d`](https://github.com/LedgerHQ/ledger-live/commit/87c160d855b512d5a0394eaee7626e2b8cd431ee), [`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`940d807`](https://github.com/LedgerHQ/ledger-live/commit/940d8073f6395cbcc2369f46aa6ad30216b00198), [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008), [`d60a022`](https://github.com/LedgerHQ/ledger-live/commit/d60a02238db9ed16142de4c1874e26d27aaaa98c), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`5de6b47`](https://github.com/LedgerHQ/ledger-live/commit/5de6b47f4fec831a24ccd58ee95d69b8c2c15d57), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`267526c`](https://github.com/LedgerHQ/ledger-live/commit/267526c3f8cc4863d4947ab3c28ba20dc5593028), [`b97b76c`](https://github.com/LedgerHQ/ledger-live/commit/b97b76cc99845b0240426f5ca75c765b615ccec5), [`1fb2b90`](https://github.com/LedgerHQ/ledger-live/commit/1fb2b909c5d97e373a0f72baa37578132bd8b24a), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`f0eb405`](https://github.com/LedgerHQ/ledger-live/commit/f0eb405b52de5484ee98ac87e87522b33836224c), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`ef99222`](https://github.com/LedgerHQ/ledger-live/commit/ef99222a5adcd9732d06600bc875309c440e084f), [`5ecbe88`](https://github.com/LedgerHQ/ledger-live/commit/5ecbe88474032b724d6c408ab63be08aa567e0fc), [`a84f3d3`](https://github.com/LedgerHQ/ledger-live/commit/a84f3d344e37301dc76f182c0f99b0b01106abfa), [`ce18c9b`](https://github.com/LedgerHQ/ledger-live/commit/ce18c9bde11fbd6cc196091716b1547354063d89), [`271f90d`](https://github.com/LedgerHQ/ledger-live/commit/271f90dc0f5b46ddaf136873dc034d4c44045dd0), [`313d0e4`](https://github.com/LedgerHQ/ledger-live/commit/313d0e42b81b69b57aa81a760465a414e6afd7f7), [`297ce51`](https://github.com/LedgerHQ/ledger-live/commit/297ce513f496f256efe8f9011734324125f462a5), [`fcd8d52`](https://github.com/LedgerHQ/ledger-live/commit/fcd8d5272176a4acec4e396ed313d3578e1c5b86), [`94afd9e`](https://github.com/LedgerHQ/ledger-live/commit/94afd9e0742d0e227b1e6ff953edee7a66ad61a3), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`1353e7a`](https://github.com/LedgerHQ/ledger-live/commit/1353e7ae02f22e8f9194a1e3c34f9444785b6fb6), [`6ccd01c`](https://github.com/LedgerHQ/ledger-live/commit/6ccd01cd738362db00c9dbc74cd0a77ccc01b206), [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037), [`bc044e4`](https://github.com/LedgerHQ/ledger-live/commit/bc044e482ea2827dca281c44ec36526d63da5194), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`8e0ac04`](https://github.com/LedgerHQ/ledger-live/commit/8e0ac04ac8cdaaee59633ebdf219e5dcf44a10df), [`cd440bb`](https://github.com/LedgerHQ/ledger-live/commit/cd440bbd647633278d983a15803032c1e676d4fe), [`c8c273c`](https://github.com/LedgerHQ/ledger-live/commit/c8c273c9a443a75b2fb85b831c8d40cf6ff068c6), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`6417959`](https://github.com/LedgerHQ/ledger-live/commit/641795937e14908ba9632a7b9744563b7e206be7), [`277648c`](https://github.com/LedgerHQ/ledger-live/commit/277648cbc0b58694a49d8d929c8ec0b89986f4cf), [`94bf322`](https://github.com/LedgerHQ/ledger-live/commit/94bf322023cf497b19399be8abcf54a57ea740d1), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`1bcff16`](https://github.com/LedgerHQ/ledger-live/commit/1bcff1673fa0cbc43f43201044d7e9425f8991f1), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`9a732c6`](https://github.com/LedgerHQ/ledger-live/commit/9a732c6d0b6e61b39f00d46c3af240640b4883e8), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`1d1bfd1`](https://github.com/LedgerHQ/ledger-live/commit/1d1bfd164847431c0f4afe7ed8ae6d5df535c9cf), [`91374dd`](https://github.com/LedgerHQ/ledger-live/commit/91374dde37f0ec3b63817254b9e26c1eb02ed981), [`042e1ab`](https://github.com/LedgerHQ/ledger-live/commit/042e1abf2d0bdbdc906cb88e30770d4de1eef356), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451), [`9abf63b`](https://github.com/LedgerHQ/ledger-live/commit/9abf63b51a159fe6c501a6b50d1e33c1551834e8), [`54578c3`](https://github.com/LedgerHQ/ledger-live/commit/54578c329baf4434f9c5d9accb8842da00e45630), [`9d58923`](https://github.com/LedgerHQ/ledger-live/commit/9d5892327b43e219b3b672e7a56e1e2d6413a83b)]:
+ - @ledgerhq/live-common@34.8.0-next.0
+ - @ledgerhq/trustchain@0.3.0-next.0
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/hw-transport-http@6.30.3-next.0
+ - @ledgerhq/hw-app-eth@6.38.1-next.0
+ - @ledgerhq/domain-service@1.2.4-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/live-wallet@0.6.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/hw-trustchain@0.1.5-next.0
+ - @ledgerhq/hw-transport@6.31.3-next.0
+ - @ledgerhq/hw-transport-web-ble@6.29.3-next.0
+ - @ledgerhq/hw-transport-webhid@6.29.3-next.0
+ - @ledgerhq/hw-transport-webusb@6.29.3-next.0
+
## 0.8.1
### Patch Changes
diff --git a/apps/web-tools/live-common-setup.ts b/apps/web-tools/live-common-setup.ts
index febf73b1d187..b157df940854 100644
--- a/apps/web-tools/live-common-setup.ts
+++ b/apps/web-tools/live-common-setup.ts
@@ -46,7 +46,6 @@ setSupportedCurrencies([
"qtum",
"bitcoin_gold",
"komodo",
- "pivx",
"zencash",
"bitcoin_testnet",
"ethereum_sepolia",
diff --git a/apps/web-tools/package.json b/apps/web-tools/package.json
index 132131a398e6..fe3f1b12b872 100644
--- a/apps/web-tools/package.json
+++ b/apps/web-tools/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/web-tools",
- "version": "0.8.1",
+ "version": "0.9.0",
"private": true,
"browser": {
"fs": false,
@@ -43,12 +43,12 @@
"eslint-config-next": "13.5.6",
"invariant": "^2.2.4",
"lodash": "^4.17.21",
- "next": "14.2.3",
+ "next": "14.2.8",
"prop-types": "^15.8.1",
"qrcode": "^1.4.4",
"re-resizable": "^6.9.11",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
"react-dropzone": "14",
"react-inspector": "^4.0.1",
"react-select": "^5.7.4",
@@ -65,8 +65,8 @@
"@types/lodash": "^4.14.198",
"@types/node": "20.8.10",
"@types/qrcode": "1",
- "@types/react": "^18.2.21",
- "@types/react-dom": "^18.2.13",
+ "@types/react": "^18.3.5",
+ "@types/react-dom": "^18.3.0",
"@types/react-inspector": "^4.0.2",
"@types/react-table": "^7.7.15",
"@types/semver": "^7.3.9"
diff --git a/apps/web-tools/repl/components/Form.tsx b/apps/web-tools/repl/components/Form.tsx
index d04bf97a5ae2..933ad2515878 100644
--- a/apps/web-tools/repl/components/Form.tsx
+++ b/apps/web-tools/repl/components/Form.tsx
@@ -1,6 +1,6 @@
import React from "react";
import FormField from "./FormField";
-import { Form } from "../helpers/commands";
+import { Form as FormType } from "../helpers/commands";
const Form = ({
form,
@@ -8,7 +8,7 @@ const Form = ({
value,
onChange,
}: {
- form: Form;
+ form: FormType;
dependencies: Object;
value: any;
onChange: (v: any) => void;
diff --git a/apps/web-tools/trustchain/components/App.tsx b/apps/web-tools/trustchain/components/App.tsx
index 0896e3dd8ddd..fc601875203c 100644
--- a/apps/web-tools/trustchain/components/App.tsx
+++ b/apps/web-tools/trustchain/components/App.tsx
@@ -2,6 +2,7 @@ import dynamic from "next/dynamic";
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
import { Tooltip } from "react-tooltip";
+import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { MemberCredentials, Trustchain, TrustchainMember } from "@ledgerhq/trustchain/types";
import { getInitialStore } from "@ledgerhq/trustchain/store";
import useEnv from "../useEnv";
@@ -113,7 +114,7 @@ const App = () => {
);
const sdk = useMemo(
- () => getSdk(!!mockEnv, context, lifecycle),
+ () => getSdk(!!mockEnv, context, withDevice, lifecycle),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
mockEnv,
@@ -266,6 +267,7 @@ const App = () => {
diff --git a/apps/web-tools/trustchain/components/AppGetOrCreateTrustchain.tsx b/apps/web-tools/trustchain/components/AppGetOrCreateTrustchain.tsx
index cc3042856444..69fd61a077a0 100644
--- a/apps/web-tools/trustchain/components/AppGetOrCreateTrustchain.tsx
+++ b/apps/web-tools/trustchain/components/AppGetOrCreateTrustchain.tsx
@@ -7,7 +7,6 @@ import {
} from "@ledgerhq/trustchain/types";
import { Actionable } from "./Actionable";
import { useTrustchainSDK } from "../context";
-import { runWithDevice } from "../device";
export function AppGetOrCreateTrustchain({
deviceId,
@@ -26,11 +25,9 @@ export function AppGetOrCreateTrustchain({
const action = useCallback(
(memberCredentials: MemberCredentials) =>
- runWithDevice(deviceId, transport =>
- sdk
- .getOrCreateTrustchain(transport, memberCredentials, callbacks)
- .then(result => result.trustchain),
- ),
+ sdk
+ .getOrCreateTrustchain(deviceId, memberCredentials, callbacks)
+ .then(result => result.trustchain),
[deviceId, sdk, callbacks],
);
diff --git a/apps/web-tools/trustchain/components/AppMemberRow.tsx b/apps/web-tools/trustchain/components/AppMemberRow.tsx
index 7d11e57b8428..b3f34cac6667 100644
--- a/apps/web-tools/trustchain/components/AppMemberRow.tsx
+++ b/apps/web-tools/trustchain/components/AppMemberRow.tsx
@@ -9,7 +9,6 @@ import {
import { Actionable } from "./Actionable";
import { DisplayName } from "./IdentityManager";
import { useTrustchainSDK } from "../context";
-import { runWithDevice } from "../device";
export function AppMemberRow({
deviceId,
@@ -32,13 +31,13 @@ export function AppMemberRow({
const action = useCallback(
(trustchain: Trustchain, memberCredentials: MemberCredentials) =>
- runWithDevice(deviceId, transport =>
- sdk.removeMember(transport, trustchain, memberCredentials, member, callbacks),
- ).then(async trustchain => {
- setTrustchain(trustchain);
- await sdk.getMembers(trustchain, memberCredentials).then(setMembers);
- return member;
- }),
+ sdk
+ .removeMember(deviceId, trustchain, memberCredentials, member, callbacks)
+ .then(async trustchain => {
+ setTrustchain(trustchain);
+ await sdk.getMembers(trustchain, memberCredentials).then(setMembers);
+ return member;
+ }),
[deviceId, sdk, member, setTrustchain, setMembers, callbacks],
);
@@ -50,7 +49,7 @@ export function AppMemberRow({
inputs={trustchain && memberCredentials ? [trustchain, memberCredentials] : null}
action={action}
value={member}
- valueDisplay={member => }
+ valueDisplay={member => }
buttonProps={{
"data-tooltip-id": "tooltip",
"data-tooltip-content":
diff --git a/apps/web-tools/trustchain/components/AppQRCodeCandidate.tsx b/apps/web-tools/trustchain/components/AppQRCodeCandidate.tsx
index ff1b68a382c4..d1053f74d621 100644
--- a/apps/web-tools/trustchain/components/AppQRCodeCandidate.tsx
+++ b/apps/web-tools/trustchain/components/AppQRCodeCandidate.tsx
@@ -1,18 +1,22 @@
import React, { useCallback, useState } from "react";
import { createQRCodeCandidateInstance } from "@ledgerhq/trustchain/qrcode/index";
-import { InvalidDigitsError } from "@ledgerhq/trustchain/errors";
+import { InvalidDigitsError, NoTrustchainInitialized } from "@ledgerhq/trustchain/errors";
import { MemberCredentials, Trustchain } from "@ledgerhq/trustchain/types";
import { Actionable } from "./Actionable";
import { memberNameForPubKey } from "./IdentityManager";
import { Input } from "./Input";
+import { useTrustchainSDK } from "../context";
export function AppQRCodeCandidate({
memberCredentials,
setTrustchain,
+ trustchain,
}: {
memberCredentials: MemberCredentials | null;
setTrustchain: (trustchain: Trustchain | null) => void;
+ trustchain: Trustchain | null;
}) {
+ const sdk = useTrustchainSDK();
const [scannedUrl, setScannedUrl] = useState(null);
const [input, setInput] = useState(null);
const [digits, setDigits] = useState(null);
@@ -33,9 +37,19 @@ export function AppQRCodeCandidate({
scannedUrl,
memberName: memberNameForPubKey(memberCredentials.pubkey),
onRequestQRCodeInput,
+ addMember: async member => {
+ if (trustchain) {
+ await sdk.addMember(trustchain, memberCredentials, member);
+ return trustchain;
+ }
+ throw new NoTrustchainInitialized();
+ },
+ initialTrustchainId: trustchain?.rootId,
})
.then(trustchain => {
- setTrustchain(trustchain);
+ if (trustchain) {
+ setTrustchain(trustchain);
+ }
return true;
})
.catch(e => {
@@ -54,7 +68,7 @@ export function AppQRCodeCandidate({
setInputCallback(null);
});
},
- [onRequestQRCodeInput, setTrustchain],
+ [onRequestQRCodeInput, sdk, setTrustchain, trustchain],
);
const handleSendDigits = useCallback(
diff --git a/apps/web-tools/trustchain/components/AppQRCodeHost.tsx b/apps/web-tools/trustchain/components/AppQRCodeHost.tsx
index 55cad8bb0855..cbfb3ce6b820 100644
--- a/apps/web-tools/trustchain/components/AppQRCodeHost.tsx
+++ b/apps/web-tools/trustchain/components/AppQRCodeHost.tsx
@@ -1,6 +1,6 @@
import React, { useCallback, useState } from "react";
import { createQRCodeHostInstance } from "@ledgerhq/trustchain/qrcode/index";
-import { InvalidDigitsError } from "@ledgerhq/trustchain/errors";
+import { InvalidDigitsError, NoTrustchainInitialized } from "@ledgerhq/trustchain/errors";
import { MemberCredentials, Trustchain } from "@ledgerhq/trustchain/types";
import { RenderActionable } from "./Actionable";
import QRCode from "./QRCode";
@@ -30,9 +30,15 @@ export function AppQRCodeHost({
setDigits(digits);
},
addMember: async member => {
- await sdk.addMember(trustchain, memberCredentials, member);
- return trustchain;
+ if (trustchain) {
+ await sdk.addMember(trustchain, memberCredentials, member);
+ return trustchain;
+ }
+ throw new NoTrustchainInitialized();
},
+ memberCredentials,
+ memberName: "WebTools",
+ initialTrustchainId: trustchain.rootId,
})
.catch(e => {
if (e instanceof InvalidDigitsError) {
diff --git a/apps/web-tools/trustchain/components/IdentityManager.tsx b/apps/web-tools/trustchain/components/IdentityManager.tsx
index a540ed7a859a..0541c76b23bb 100644
--- a/apps/web-tools/trustchain/components/IdentityManager.tsx
+++ b/apps/web-tools/trustchain/components/IdentityManager.tsx
@@ -32,11 +32,17 @@ type Identities = { [_: string]: TrustchainStore };
const initialObject: Identities = {};
-export function DisplayName({ pubkey }: { pubkey?: string }) {
+export function DisplayName({
+ pubkey,
+ overridesName,
+}: {
+ pubkey?: string;
+ overridesName?: string;
+}) {
if (!pubkey) return null;
return (
<>
- {memberNameForPubKey(pubkey)}
+ {overridesName || memberNameForPubKey(pubkey)}
>
);
}
diff --git a/apps/web-tools/trustchain/context.ts b/apps/web-tools/trustchain/context.ts
index 422fb0c77c2b..69c69f0a2153 100644
--- a/apps/web-tools/trustchain/context.ts
+++ b/apps/web-tools/trustchain/context.ts
@@ -1,4 +1,5 @@
import React, { useContext } from "react";
+import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
import { TrustchainSDK } from "@ledgerhq/trustchain/types";
import { getSdk } from "@ledgerhq/trustchain/index";
import { getEnv } from "@ledgerhq/live-env";
@@ -10,7 +11,7 @@ export const defaultContext = {
};
export const TrustchainSDKContext = React.createContext(
- getSdk(false, defaultContext),
+ getSdk(false, defaultContext, withDevice),
);
export const useTrustchainSDK = () => useContext(TrustchainSDKContext);
diff --git a/apps/web-tools/trustchain/device.ts b/apps/web-tools/trustchain/device.ts
deleted file mode 100644
index a3c066828f3a..000000000000
--- a/apps/web-tools/trustchain/device.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess";
-import { from, lastValueFrom } from "rxjs";
-import Transport from "@ledgerhq/hw-transport";
-
-export function runWithDevice(
- deviceId: string,
- fn: (transport: Transport) => Promise,
-): Promise {
- return lastValueFrom(withDevice(deviceId)(transport => from(fn(transport))));
-}
diff --git a/libs/coin-framework/.unimportedrc.json b/libs/coin-framework/.unimportedrc.json
index 2179c7fde8cb..7a4d52c796af 100644
--- a/libs/coin-framework/.unimportedrc.json
+++ b/libs/coin-framework/.unimportedrc.json
@@ -25,5 +25,9 @@
"src/test-helpers/bridge-integration-suite.ts",
"src/config.ts"
],
- "ignoreUnresolved": ["follow-redirects"]
-}
+ "ignoreUnresolved": [
+ "follow-redirects",
+ "form-data",
+ "proxy-from-env"
+ ]
+}
\ No newline at end of file
diff --git a/libs/coin-framework/CHANGELOG.md b/libs/coin-framework/CHANGELOG.md
index 7f346f20a6e0..c0380e125f59 100644
--- a/libs/coin-framework/CHANGELOG.md
+++ b/libs/coin-framework/CHANGELOG.md
@@ -1,5 +1,51 @@
# @ledgerhq/coin-framework
+## 0.18.0
+
+### Minor Changes
+
+- [#7268](https://github.com/LedgerHQ/ledger-live/pull/7268) [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Prepare CoinModule Stellar for Alpaca
+
+### Patch Changes
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.18.0-next.0
+
+### Minor Changes
+
+- [#7268](https://github.com/LedgerHQ/ledger-live/pull/7268) [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Prepare CoinModule Stellar for Alpaca
+
+### Patch Changes
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.17.0
### Minor Changes
diff --git a/libs/coin-framework/package.json b/libs/coin-framework/package.json
index 581f7ffa2d47..3426c3460e64 100644
--- a/libs/coin-framework/package.json
+++ b/libs/coin-framework/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-framework",
- "version": "0.17.0",
+ "version": "0.18.0",
"description": "Ledger framework for Coin integration",
"keywords": [
"Ledger",
diff --git a/libs/coin-framework/src/api/types.ts b/libs/coin-framework/src/api/types.ts
index fd9a5159095d..58be941507b6 100644
--- a/libs/coin-framework/src/api/types.ts
+++ b/libs/coin-framework/src/api/types.ts
@@ -17,17 +17,18 @@ export type Operation = {
transactionSequenceNumber: number;
};
+export type Transaction = {
+ mode: string;
+ recipient: string;
+ amount: bigint;
+ fee: bigint;
+ supplement?: unknown;
+};
+
export type Api = {
broadcast: (tx: string) => Promise;
combine: (tx: string, signature: string, pubkey?: string) => string;
- craftTransaction: (
- address: string,
- transaction: {
- recipient: string;
- amount: bigint;
- fee: bigint;
- },
- ) => Promise;
+ craftTransaction: (address: string, transaction: Transaction, pubkey?: string) => Promise;
estimateFees: (addr: string, amount: bigint) => Promise;
getBalance: (address: string) => Promise;
lastBlock: () => Promise;
diff --git a/libs/coin-framework/src/config.ts b/libs/coin-framework/src/config.ts
index d108a2de171b..a1e5ed522485 100644
--- a/libs/coin-framework/src/config.ts
+++ b/libs/coin-framework/src/config.ts
@@ -1,3 +1,4 @@
+import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
import { MissingCoinConfig } from "./errors";
type ConfigStatus =
@@ -21,7 +22,7 @@ export type CurrencyConfig = {
[key: string]: unknown;
};
-export type CoinConfig = () => T;
+export type CoinConfig = (currency?: CryptoCurrency) => T;
function buildCoinConfig() {
let coinConfig: CoinConfig | undefined;
@@ -30,12 +31,12 @@ function buildCoinConfig() {
coinConfig = config;
};
- const getCoinConfig = (): T => {
+ const getCoinConfig = (currency?: CryptoCurrency): T => {
if (!coinConfig) {
throw new MissingCoinConfig();
}
- return coinConfig();
+ return coinConfig(currency);
};
return {
diff --git a/libs/coin-framework/src/currencies/__snapshots__/formatCurrencyUnit.test.ts.snap b/libs/coin-framework/src/currencies/__snapshots__/formatCurrencyUnit.test.ts.snap
index f0e049bd042b..f243f9932eca 100644
--- a/libs/coin-framework/src/currencies/__snapshots__/formatCurrencyUnit.test.ts.snap
+++ b/libs/coin-framework/src/currencies/__snapshots__/formatCurrencyUnit.test.ts.snap
@@ -226,11 +226,9 @@ exports[`formatCurrencyUnit with custom options with locale de-DE should correct
exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format Pirl unit (PIRL) 1`] = `"123.456.789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format PivX unit (pivx) 1`] = `"123.456.789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format Polkadot unit (DOT) 1`] = `"1.234.567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale de-DE should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -552,11 +550,9 @@ exports[`formatCurrencyUnit with custom options with locale en-US should correct
exports[`formatCurrencyUnit with custom options with locale en-US should correctly format Pirl unit (PIRL) 1`] = `"123,456,789.00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale en-US should correctly format PivX unit (pivx) 1`] = `"123,456,789.00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale en-US should correctly format Polkadot unit (DOT) 1`] = `"1,234,567.8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale en-US should correctly format Polygon unit (MATIC) 1`] = `"0.012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale en-US should correctly format Polygon unit (POL) 1`] = `"0.012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale en-US should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0.012345678900000000- -𝚝ETH"`;
@@ -878,11 +874,9 @@ exports[`formatCurrencyUnit with custom options with locale es-ES should correct
exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format Pirl unit (PIRL) 1`] = `"123.456.789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format PivX unit (pivx) 1`] = `"123.456.789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format Polkadot unit (DOT) 1`] = `"1.234.567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale es-ES should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -1204,11 +1198,9 @@ exports[`formatCurrencyUnit with custom options with locale fr-FR should correct
exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format Pirl unit (PIRL) 1`] = `"123 456 789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format PivX unit (pivx) 1`] = `"123 456 789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format Polkadot unit (DOT) 1`] = `"1 234 567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale fr-FR should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -1530,11 +1522,9 @@ exports[`formatCurrencyUnit with custom options with locale ja-JP should correct
exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format Pirl unit (PIRL) 1`] = `"123,456,789.00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format PivX unit (pivx) 1`] = `"123,456,789.00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format Polkadot unit (DOT) 1`] = `"1,234,567.8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format Polygon unit (MATIC) 1`] = `"0.012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format Polygon unit (POL) 1`] = `"0.012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale ja-JP should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0.012345678900000000- -𝚝ETH"`;
@@ -1856,11 +1846,9 @@ exports[`formatCurrencyUnit with custom options with locale ko-KR should correct
exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format Pirl unit (PIRL) 1`] = `"123,456,789.00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format PivX unit (pivx) 1`] = `"123,456,789.00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format Polkadot unit (DOT) 1`] = `"1,234,567.8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format Polygon unit (MATIC) 1`] = `"0.012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format Polygon unit (POL) 1`] = `"0.012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale ko-KR should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0.012345678900000000- -𝚝ETH"`;
@@ -2182,11 +2170,9 @@ exports[`formatCurrencyUnit with custom options with locale pt-BR should correct
exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format Pirl unit (PIRL) 1`] = `"123.456.789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format PivX unit (pivx) 1`] = `"123.456.789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format Polkadot unit (DOT) 1`] = `"1.234.567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale pt-BR should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -2508,11 +2494,9 @@ exports[`formatCurrencyUnit with custom options with locale ru-RU should correct
exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format Pirl unit (PIRL) 1`] = `"123 456 789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format PivX unit (pivx) 1`] = `"123 456 789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format Polkadot unit (DOT) 1`] = `"1 234 567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale ru-RU should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -2834,11 +2818,9 @@ exports[`formatCurrencyUnit with custom options with locale tr-TR should correct
exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format Pirl unit (PIRL) 1`] = `"123.456.789,00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format PivX unit (pivx) 1`] = `"123.456.789,00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format Polkadot unit (DOT) 1`] = `"1.234.567,8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format Polygon unit (MATIC) 1`] = `"0,012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format Polygon unit (POL) 1`] = `"0,012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale tr-TR should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0,012345678900000000- -𝚝ETH"`;
@@ -3160,11 +3142,9 @@ exports[`formatCurrencyUnit with custom options with locale zh-CN should correct
exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format Pirl unit (PIRL) 1`] = `"123,456,789.00000000- -PIRL"`;
-exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format PivX unit (pivx) 1`] = `"123,456,789.00000000- -PIVX"`;
-
exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format Polkadot unit (DOT) 1`] = `"1,234,567.8900000000- -DOT"`;
-exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format Polygon unit (MATIC) 1`] = `"0.012345678900000000- -MATIC"`;
+exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format Polygon unit (POL) 1`] = `"0.012345678900000000- -POL"`;
exports[`formatCurrencyUnit with custom options with locale zh-CN should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0.012345678900000000- -𝚝ETH"`;
@@ -3486,11 +3466,9 @@ exports[`formatCurrencyUnit with default options should correctly format Persist
exports[`formatCurrencyUnit with default options should correctly format Pirl unit (PIRL) 1`] = `"123,456,789"`;
-exports[`formatCurrencyUnit with default options should correctly format PivX unit (pivx) 1`] = `"123,456,789"`;
-
exports[`formatCurrencyUnit with default options should correctly format Polkadot unit (DOT) 1`] = `"1,234,567"`;
-exports[`formatCurrencyUnit with default options should correctly format Polygon unit (MATIC) 1`] = `"0.0123456"`;
+exports[`formatCurrencyUnit with default options should correctly format Polygon unit (POL) 1`] = `"0.0123456"`;
exports[`formatCurrencyUnit with default options should correctly format Polygon zkEVM Testnet unit (ETH) 1`] = `"0.0123456"`;
diff --git a/libs/coin-modules/README.md b/libs/coin-modules/README.md
new file mode 100644
index 000000000000..ade1d3de33f9
--- /dev/null
+++ b/libs/coin-modules/README.md
@@ -0,0 +1,41 @@
+Coin Modules
+============
+
+Alpaca compatibility
+--------------------
+
+### Architectural Decision
+The following concepts are mandatory for a CoinModule to be *Alpaca compliant*.
+#### A CoinModule has the following directories/modules
+* `api`: interface for exposing the CoinModule to a backend service (a.k.a. Alpaca)
+* `bridge`: implementation of Bridges interface (cf. [Bridge](light-sync))
+* `logic`: contains all core logic of the blockchain. The code here is agnostic of all external interface (i.e. Bridge or Api) and relies only on external libs and `network` directory
+* `network`: communication logic with explorer/index/node (cf. [How to wrap you api](light-sync#wrap-your-api))
+* `signer`: defines the interface definition to the Embedded App and the logic to retrieve [derive address](addrss-derivation)
+* `types`: all different model definitions, except for `network`
+
+**==> With this organisation, it is more obvious and consistent where to find and create new functions/files.**
+
+#### The model types has to follow those rules
+* `network` types are defined in its module.
+* `network` types can only be used within its module.
+* `logic` types are defined in `types` module
+* `logic` types can be used within in any module (except `network` due to it voluntary "lack" of visibility)
+* `bridge` types are defined in `types` module
+* `bridge` types can only be used within its module
+* `api` types are defined in `types` module
+* `api` types can only be used within its module
+
+**==> By creating this separation, we avoid any colision between Bridge types (a.k.a. Live types) in Alpaca interface and vice versa.**
+
+#### Network calls
+`network` functions should only be accessed through the `logic` module. *This is an on-going effort*.
+
+**==> By creating this layer, we enforce the consistency between `bridge` behaviour and `api` behaviour.**
+
+### Status
+List of CoinModule compatible with Alpaca:
+* Polkadot
+* Stellar
+* Tezos
+* Xrp
diff --git a/libs/coin-modules/coin-algorand/CHANGELOG.md b/libs/coin-modules/coin-algorand/CHANGELOG.md
index 694d3e88f3cd..220339a017d1 100644
--- a/libs/coin-modules/coin-algorand/CHANGELOG.md
+++ b/libs/coin-modules/coin-algorand/CHANGELOG.md
@@ -1,5 +1,33 @@
# @ledgerhq/coin-algorand
+## 0.5.5
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.5.5-next.0
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.5.4
### Patch Changes
diff --git a/libs/coin-modules/coin-algorand/package.json b/libs/coin-modules/coin-algorand/package.json
index d69d0664a4a1..488cfbe4c767 100644
--- a/libs/coin-modules/coin-algorand/package.json
+++ b/libs/coin-modules/coin-algorand/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-algorand",
- "version": "0.5.4",
+ "version": "0.5.5",
"description": "Ledger Algorand Coin integration",
"keywords": [
"Ledger",
diff --git a/libs/coin-modules/coin-bitcoin/.unimportedrc.json b/libs/coin-modules/coin-bitcoin/.unimportedrc.json
index 4d4a171cae74..e4fb849aa0f6 100644
--- a/libs/coin-modules/coin-bitcoin/.unimportedrc.json
+++ b/libs/coin-modules/coin-bitcoin/.unimportedrc.json
@@ -18,7 +18,6 @@
"src/datasets/dogecoin.ts",
"src/datasets/litecoin.scanAccounts.1.ts",
"src/datasets/litecoin.ts",
- "src/datasets/pivx.ts",
"src/datasets/zcash.ts",
"src/datasets/zencash.ts",
"src/descriptor.ts",
diff --git a/libs/coin-modules/coin-bitcoin/CHANGELOG.md b/libs/coin-modules/coin-bitcoin/CHANGELOG.md
index 149ab313e92e..1a0607097744 100644
--- a/libs/coin-modules/coin-bitcoin/CHANGELOG.md
+++ b/libs/coin-modules/coin-bitcoin/CHANGELOG.md
@@ -1,5 +1,53 @@
# @ledgerhq/coin-bitcoin
+## 0.8.0
+
+### Minor Changes
+
+- [#7742](https://github.com/LedgerHQ/ledger-live/pull/7742) [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: some issue with btc custom fees when reopening drawer
+
+### Patch Changes
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7536](https://github.com/LedgerHQ/ledger-live/pull/7536) [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d) Thanks [@Wozacosta](https://github.com/Wozacosta)! - adds some unit tests in coin-bitcoin coin-module
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.8.0-next.0
+
+### Minor Changes
+
+- [#7742](https://github.com/LedgerHQ/ledger-live/pull/7742) [`e6b8cea`](https://github.com/LedgerHQ/ledger-live/commit/e6b8ceac486147f4000aab7f0ae7f89d2ac205b1) Thanks [@CremaFR](https://github.com/CremaFR)! - fix: some issue with btc custom fees when reopening drawer
+
+### Patch Changes
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7536](https://github.com/LedgerHQ/ledger-live/pull/7536) [`d2f7d9b`](https://github.com/LedgerHQ/ledger-live/commit/d2f7d9b418c374bd6b87927c1f67d58c118b556d) Thanks [@Wozacosta](https://github.com/Wozacosta)! - adds some unit tests in coin-bitcoin coin-module
+
+- [#7563](https://github.com/LedgerHQ/ledger-live/pull/7563) [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4) Thanks [@Wozacosta](https://github.com/Wozacosta)! - remove pivx code
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.7.3
### Patch Changes
diff --git a/libs/coin-modules/coin-bitcoin/jest.config.js b/libs/coin-modules/coin-bitcoin/jest.config.js
index f1b2df2b8018..abe07c3fa244 100644
--- a/libs/coin-modules/coin-bitcoin/jest.config.js
+++ b/libs/coin-modules/coin-bitcoin/jest.config.js
@@ -5,4 +5,5 @@ module.exports = {
preset: "ts-jest",
testEnvironment: "node",
testPathIgnorePatterns: ["lib/", "lib-es/", ".integration.test.ts"],
+ modulePathIgnorePatterns: ["__tests__/fixtures"],
};
diff --git a/libs/coin-modules/coin-bitcoin/package.json b/libs/coin-modules/coin-bitcoin/package.json
index af3c311bb43e..5524ab27777d 100644
--- a/libs/coin-modules/coin-bitcoin/package.json
+++ b/libs/coin-modules/coin-bitcoin/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-bitcoin",
- "version": "0.7.3",
+ "version": "0.8.0",
"description": "Ledger Bitcoin Coin integration",
"keywords": [
"Ledger",
@@ -86,7 +86,7 @@
"@types/ripemd160": "^2.0.3",
"@types/secp256k1": "^4.0.3",
"@types/sha.js": "^2.4.4",
- "axios": "0.26.1",
+ "axios": "1.7.3",
"bip32": "^2.0.6",
"bip39": "^3.0.4",
"jest": "^29.7.0",
diff --git a/libs/coin-modules/coin-bitcoin/src/__tests__/fixtures/common.fixtures.ts b/libs/coin-modules/coin-bitcoin/src/__tests__/fixtures/common.fixtures.ts
new file mode 100644
index 000000000000..02a6acdf41a3
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/__tests__/fixtures/common.fixtures.ts
@@ -0,0 +1,175 @@
+import BigNumber from "bignumber.js";
+import { listCryptoCurrencies } from "@ledgerhq/cryptoassets/currencies";
+import { emptyHistoryCache } from "@ledgerhq/coin-framework/account/index";
+import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
+import { BitcoinAccount, BitcoinResources, NetworkInfoRaw } from "../../types";
+import {
+ AddressFormat,
+ BitcoinAddress,
+ BitcoinSignature,
+ BitcoinSigner,
+ BitcoinXPub,
+ CreateTransaction,
+ SignerTransaction,
+} from "../../signer";
+
+export const networkInfo: NetworkInfoRaw = {
+ family: "bitcoin",
+ feeItems: {
+ items: [
+ {
+ key: "0",
+ speed: "high",
+ feePerByte: "3",
+ },
+ {
+ key: "1",
+ speed: "standard",
+ feePerByte: "2",
+ },
+ {
+ key: "2",
+ speed: "low",
+ feePerByte: "1",
+ },
+ ],
+ defaultFeePerByte: "1",
+ },
+};
+
+export function createFixtureAccount(account?: Partial): BitcoinAccount {
+ const currency = listCryptoCurrencies(true).find(c => c.id === "bitcoin")!;
+
+ const bitcoinResources: BitcoinResources = account?.bitcoinResources || {
+ utxos: [],
+ };
+
+ const freshAddress = {
+ address: "1fMK6i7CMDES1GNGDEMX5ddDaxbkjWPw1M",
+ derivationPath: "derivation_path",
+ };
+
+ return {
+ type: "Account",
+ id: "E0A538D5-5EE7-4E37-BB57-F373B08B8580",
+ seedIdentifier: "FD5EAFE3-8C7F-4565-ADFA-2A1A2067322A",
+ derivationMode: "",
+ index: 0,
+ freshAddress: freshAddress.address,
+ freshAddressPath: freshAddress.derivationPath,
+ used: true,
+ balance: account?.balance || new BigNumber(0),
+ spendableBalance: account?.spendableBalance || new BigNumber(0),
+ creationDate: new Date(),
+ blockHeight: 100_000,
+ currency,
+ operationsCount: 0,
+ operations: [],
+ pendingOperations: [],
+ lastSyncDate: new Date(),
+ balanceHistoryCache: emptyHistoryCache,
+ swapHistory: [],
+
+ bitcoinResources,
+ };
+}
+
+export const mockXpubPubKey = {
+ xpub: [
+ "xpub6DEHKg8fgKcb5iYGPLtpBYD9gm7nvym3wwhHVnH3TtogvJGTcApj71K8iTpL7CzdZWAxwyjkZEFUrnLK24zKqgj3EVH7Vg1CD1ujibwiHuy",
+ ],
+ pubKey: [
+ {
+ publicKey:
+ "xpub6DEHKg8fgKcb5iYGPLtpBYD9gm7nvym3wwhHVnH3TtogvJGTcApj71K8iTpL7CzdZWAxwyjkZEFUrnLK24zKqgj3EVH7Vg1CD1ujibwiHuy",
+ bitcoinAddress: "bc1qhh568mfmwu7ymvwhu5e4mttpfg4ehxfpvhjs64",
+ chainCode: "",
+ },
+ ],
+};
+
+export const mockSigner: BitcoinSigner = {
+ getWalletXpub: (_arg: { path: string; xpubVersion: number }): Promise =>
+ Promise.resolve(""),
+ getWalletPublicKey: (
+ _path: string,
+ _opts?: {
+ verify?: boolean;
+ format?: AddressFormat;
+ },
+ ): Promise => {
+ return Promise.resolve({
+ publicKey: "",
+ bitcoinAddress: "",
+ chainCode: "",
+ });
+ },
+ signMessage: (_path: string, _messageHex: string): Promise =>
+ Promise.resolve({
+ v: 0,
+ r: "123",
+ s: "456",
+ }),
+ splitTransaction: (
+ _transactionHex: string,
+ _isSegwitSupported: boolean | null | undefined,
+ _hasExtraData: boolean | null | undefined,
+ _additionals: Array | null | undefined,
+ ): SignerTransaction => ({
+ version: Buffer.from(""),
+ inputs: [
+ {
+ prevout: Buffer.from(""),
+ script: Buffer.from(""),
+ sequence: Buffer.from(""),
+ },
+ ],
+ }),
+ createPaymentTransaction: (_arg: CreateTransaction): Promise =>
+ Promise.resolve("createPaymentTransactionReturn"),
+};
+
+export const mockSignerContext = (
+ _deviceId: string,
+ _crypto: CryptoCurrency,
+ fn: (signer: BitcoinSigner) => Promise,
+): Promise =>
+ fn({
+ getWalletXpub: (_arg: { path: string; xpubVersion: number }): Promise =>
+ Promise.resolve(""),
+ getWalletPublicKey: (
+ _path: string,
+ _opts?: {
+ verify?: boolean;
+ format?: AddressFormat;
+ },
+ ): Promise => {
+ return Promise.resolve({
+ publicKey: "",
+ bitcoinAddress: "",
+ chainCode: "",
+ });
+ },
+ signMessage: (_path: string, _messageHex: string): Promise =>
+ Promise.resolve({
+ v: 0,
+ r: "123",
+ s: "456",
+ }),
+ splitTransaction: (
+ _transactionHex: string,
+ _isSegwitSupported: boolean | null | undefined,
+ _hasExtraData: boolean | null | undefined,
+ _additionals: Array | null | undefined,
+ ): SignerTransaction => ({
+ version: Buffer.from(""),
+ inputs: [
+ {
+ prevout: Buffer.from(""),
+ script: Buffer.from(""),
+ sequence: Buffer.from(""),
+ },
+ ],
+ }),
+ createPaymentTransaction: (_arg: CreateTransaction): Promise => Promise.resolve(""),
+ });
diff --git a/libs/coin-modules/coin-bitcoin/src/__tests__/unit/buildTransaction.unit.test.ts b/libs/coin-modules/coin-bitcoin/src/__tests__/unit/buildTransaction.unit.test.ts
new file mode 100644
index 000000000000..55ea9ab2c8e7
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/__tests__/unit/buildTransaction.unit.test.ts
@@ -0,0 +1,72 @@
+import { FeeNotLoaded } from "@ledgerhq/errors";
+
+import { bitcoinPickingStrategy } from "../../types";
+import wallet, { TransactionInfo } from "../../wallet-btc";
+import { fromTransactionRaw } from "../../transaction";
+import { buildTransaction } from "../../buildTransaction";
+
+import { createFixtureAccount, networkInfo } from "../fixtures/common.fixtures";
+
+jest.mock("../../wallet-btc", () => ({
+ ...jest.requireActual("../../wallet-btc"),
+ getWalletAccount: jest.fn().mockReturnValue({
+ xpub: {
+ crypto: "bitcoin",
+ },
+ }),
+}));
+
+describe("buildTransaction", () => {
+ const mockAccount = createFixtureAccount();
+ const maxSpendable = 100000;
+ const txInfo = {
+ inputs: [],
+ outputs: [],
+ fee: 0,
+ associatedDerivations: [],
+ changeAddress: { address: "change-address", account: 1, index: 1 },
+ } as TransactionInfo;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ wallet.estimateAccountMaxSpendable = jest.fn().mockResolvedValue(maxSpendable);
+ wallet.buildAccountTx = jest.fn().mockResolvedValue(txInfo);
+ });
+ it("should throw FeeNotLoaded if feePerByte is not provided", async () => {
+ const transaction = fromTransactionRaw({
+ family: "bitcoin",
+ recipient: "1Cz2ZXb6Y6AacXJTpo4RBjQMLEmscuxD8e",
+ amount: "999",
+ feePerByte: null,
+ networkInfo,
+ rbf: false,
+ utxoStrategy: {
+ strategy: bitcoinPickingStrategy.MERGE_OUTPUTS,
+ excludeUTXOs: [],
+ },
+ });
+
+ await expect(buildTransaction(mockAccount, transaction)).rejects.toThrow(FeeNotLoaded);
+ });
+
+ it("should call getWalletAccount with the provided account", async () => {
+ const transaction = fromTransactionRaw({
+ family: "bitcoin",
+ recipient: "1Cz2ZXb6Y6AacXJTpo4RBjQMLEmscuxD8e",
+ amount: "999",
+ feePerByte: "1",
+ networkInfo,
+ rbf: false,
+ utxoStrategy: {
+ strategy: bitcoinPickingStrategy.MERGE_OUTPUTS,
+ excludeUTXOs: [],
+ },
+ });
+
+ const res = await buildTransaction(mockAccount, transaction);
+
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ expect(require("../../wallet-btc").getWalletAccount).toHaveBeenCalledWith(mockAccount);
+ expect(res).toEqual(txInfo);
+ });
+});
diff --git a/libs/coin-modules/coin-bitcoin/src/__tests__/unit/synchronisation.unit.test.ts b/libs/coin-modules/coin-bitcoin/src/__tests__/unit/synchronisation.unit.test.ts
new file mode 100644
index 000000000000..5da2d31e196b
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/__tests__/unit/synchronisation.unit.test.ts
@@ -0,0 +1,60 @@
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
+import { makeGetAccountShape } from "../../synchronisation";
+
+import { createFixtureAccount, mockSignerContext } from "../fixtures/common.fixtures";
+
+describe("synchronisation", () => {
+ it("should return a function", () => {
+ const result = makeGetAccountShape(mockSignerContext);
+ expect(typeof result).toBe("function");
+ });
+
+ it("should return an account shape with the correct properties", async () => {
+ const getAccountShape = makeGetAccountShape(mockSignerContext);
+ const mockAccount = createFixtureAccount();
+ mockAccount.id =
+ "js:2:bitcoin:xpub6DM4oxVnZiePFvQMu1RJLQwWUzZQP3UNaLqrGcbJQkAJZYdiRoRivHULWoYN3zBYU4mJRpM3WrGaqo1kS8Q2XFfd9E3QEc9P3MKHwbHz9LB:native_segwit";
+ const result = await getAccountShape(
+ {
+ currency: getCryptoCurrencyById("bitcoin"),
+ address: "0x123",
+ index: 1,
+ derivationPath: "m/44'/0'/0'/0/1",
+ derivationMode: "taproot",
+ initialAccount: mockAccount,
+ },
+ { paginationConfig: {} },
+ );
+ expect(result).toMatchObject({
+ bitcoinResources: {
+ utxos: [],
+ walletAccount: {
+ params: {
+ currency: "bitcoin",
+ derivationMode: "Taproot",
+ index: 1,
+ network: "mainnet",
+ path: "m/44'",
+ xpub: "xpub6DM4oxVnZiePFvQMu1RJLQwWUzZQP3UNaLqrGcbJQkAJZYdiRoRivHULWoYN3zBYU4mJRpM3WrGaqo1kS8Q2XFfd9E3QEc9P3MKHwbHz9LB",
+ },
+ xpub: {
+ GAP: 20,
+ OUTPUT_VALUE_MAX: 9007199254740991,
+ derivationMode: "Taproot",
+ explorer: { baseUrl: "https://explorers.api.live.ledger.com/blockchain/v4/btc" },
+ freshAddress: "bc1pusjmg6xjpym8t8rvdw5gyx2mxvqj0l439acqzy2ssv546k857svqdnth09",
+ freshAddressIndex: 0,
+ txsSyncArraySize: 1000,
+ xpub: "xpub6DM4oxVnZiePFvQMu1RJLQwWUzZQP3UNaLqrGcbJQkAJZYdiRoRivHULWoYN3zBYU4mJRpM3WrGaqo1kS8Q2XFfd9E3QEc9P3MKHwbHz9LB",
+ },
+ },
+ },
+ freshAddress: "bc1pusjmg6xjpym8t8rvdw5gyx2mxvqj0l439acqzy2ssv546k857svqdnth09",
+ freshAddressPath: "m/44'/1'/0/0",
+ id: "js:2:bitcoin:xpub6DM4oxVnZiePFvQMu1RJLQwWUzZQP3UNaLqrGcbJQkAJZYdiRoRivHULWoYN3zBYU4mJRpM3WrGaqo1kS8Q2XFfd9E3QEc9P3MKHwbHz9LB:taproot",
+ operations: [],
+ operationsCount: 0,
+ xpub: "xpub6DM4oxVnZiePFvQMu1RJLQwWUzZQP3UNaLqrGcbJQkAJZYdiRoRivHULWoYN3zBYU4mJRpM3WrGaqo1kS8Q2XFfd9E3QEc9P3MKHwbHz9LB",
+ });
+ });
+});
diff --git a/libs/coin-modules/coin-bitcoin/src/bridge.integration.ts b/libs/coin-modules/coin-bitcoin/src/bridge.integration.ts
index 4761f45e0dab..b0978c00c232 100644
--- a/libs/coin-modules/coin-bitcoin/src/bridge.integration.ts
+++ b/libs/coin-modules/coin-bitcoin/src/bridge.integration.ts
@@ -11,7 +11,6 @@ import digibyte from "./datasets/digibyte";
import dogecoin from "./datasets/dogecoin";
import zencash from "./datasets/zencash";
import litecoin from "./datasets/litecoin";
-import pivx from "./datasets/pivx";
import zcash from "./datasets/zcash";
/*
@@ -41,7 +40,6 @@ export const dataset: DatasetTest = {
dogecoin,
zencash,
litecoin,
- pivx,
zcash,
},
};
diff --git a/libs/coin-modules/coin-bitcoin/src/datasets/pivx.ts b/libs/coin-modules/coin-bitcoin/src/datasets/pivx.ts
deleted file mode 100644
index 731926a01008..000000000000
--- a/libs/coin-modules/coin-bitcoin/src/datasets/pivx.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import type { CurrenciesData } from "@ledgerhq/types-live";
-import type { Transaction } from "../types";
-const dataset: CurrenciesData = {
- FIXME_ignoreAccountFields: [
- "bitcoinResources.walletAccount", // it is not "stable"
- "bitcoinResources.utxos", // TODO: fix ordering
- ],
- scanAccounts: [
- {
- name: "pivx seed 1",
- apdus: `
- => e04000000d038000002c8000004d80000000
- <= 410416e1de49a4dd716985e2992bfaad4e7db30a6adbf63dafbd6607e447ce9f782771ef9f6790fafb1bfd15f72c5e8988825660426546152e15b578d160128e623822444a63614d6f586a7053587061364c357833334a3169786850516a434d624e445a684f80f6a6442efedd9ac04065f1b0de7a80ded13b89ea2969211b0018995a3d929000
- => e040000015058000002c8000004d800000000000000000000000
- <= 41041a08d17e0724191cdf6c595f937a70c0170a82a2d35e0c5203aff182223dff0eb81e3f4d63cc5c5e85e9ba68f4fa96ef075a3768785ae7c6b796007bae1bb93d2244437238694c706a5a64774e5166636263536733755a5754734764544a564a385042e42e1e4738c902f9b2448fefd771bf8c51881157c23656bd1d76455e490f1d4f9000
- => e040000009028000002c8000004d
- <= 410493d3f73ba2193ced03324858f16627d6a90356042602355f7425848e31a5559354291bb8c8cd1f6dcb3a2b47dd10756b0e2e7a7056edc4610d2ea2d5461241ac2244366772344e41465653416d4868703241624c537872384b556444486b7754454c5593aae7c64f84b5c0c6c3d108dfd02815124227dfe1f05e9b51d7b8752f5069009000
- => e04000000d038000002c8000004d80000000
- <= 410416e1de49a4dd716985e2992bfaad4e7db30a6adbf63dafbd6607e447ce9f782771ef9f6790fafb1bfd15f72c5e8988825660426546152e15b578d160128e623822444a63614d6f586a7053587061364c357833334a3169786850516a434d624e445a684f80f6a6442efedd9ac04065f1b0de7a80ded13b89ea2969211b0018995a3d929000
- => e040000015058000002c8000004d800000010000000000000000
- <= 4104fc7b55b1adfe569cb48a2a81a704fed0db14a0b7194bc9df0e298e39aab3a81bb8024a0a2e410a3139dfb4c0fd02d2e49ed7c758d94de7d5eb9b65207f8dd5402244437476486451557661653944514776734631416f6157767477594a34366950646a7ea1921f604eb6f0ac1822eb41a481f441ccd5ee18d963d58567d90c1287bcb59000
- => e040000009028000002c8000004d
- <= 410493d3f73ba2193ced03324858f16627d6a90356042602355f7425848e31a5559354291bb8c8cd1f6dcb3a2b47dd10756b0e2e7a7056edc4610d2ea2d5461241ac2244366772344e41465653416d4868703241624c537872384b556444486b7754454c5593aae7c64f84b5c0c6c3d108dfd02815124227dfe1f05e9b51d7b8752f5069009000
- => e04000000d038000002c8000004d80000001
- <= 4104ae61bd55cefcfdfa57f0fd0fdfcf2b6b848a7b54ae2beeb76a790a7d11234134d43de0a76f14f4f43c8419cf18a129a10619bfff3a8cf12ea24a0655636ad1c822444c614e4653644234437862423169724168646e6b5469737872447050527051507601f823644be630276d4d23f2bd02106822f2cbec28ab62ee7ac982371abb2b909000
- => e040000015058000002c8000004d800000020000000000000000
- <= 410458c223d38ab47eac93a1d32eebe530cf3e974a8db52c06be6b021bbed2b5d454e84f1d79e8cfcf7b304fe3bf248314d7f8181877365fb724259b589423f3a8982244456f5561626d674e34654a33584d54684854315a4150656b70566672316d313746f32e72827a5a28c47d6b64f9aa7ec6175e2209f831932419997e90104644c36b9000
- => e040000009028000002c8000004d
- <= 410493d3f73ba2193ced03324858f16627d6a90356042602355f7425848e31a5559354291bb8c8cd1f6dcb3a2b47dd10756b0e2e7a7056edc4610d2ea2d5461241ac2244366772344e41465653416d4868703241624c537872384b556444486b7754454c5593aae7c64f84b5c0c6c3d108dfd02815124227dfe1f05e9b51d7b8752f5069009000
- => e04000000d038000002c8000004d80000002
- <= 4104846565697d076980dc6905a7757db628156c355101e1ee4d3a4a9d16b35e9d7e1407cd14608452ec363650f17ecbf1e4016ee47f641a68a180928b899925027622444c556272616642646d4544696f4e5172654136324b576472546f4573423354485a7d810804d11d7d2259d851474a70811226d44020992dafd905a3de029f0f23329000
- `,
- },
- ],
-};
-export default dataset;
diff --git a/libs/coin-modules/coin-bitcoin/src/getTransactionStatus.ts b/libs/coin-modules/coin-bitcoin/src/getTransactionStatus.ts
index 0102d82ce6a5..0a84f6c4d910 100644
--- a/libs/coin-modules/coin-bitcoin/src/getTransactionStatus.ts
+++ b/libs/coin-modules/coin-bitcoin/src/getTransactionStatus.ts
@@ -22,7 +22,7 @@ export const getTransactionStatus: AccountBridge<
Transaction,
Account,
TransactionStatus
->["getTransactionStatus"] = async (account, transaction) => {
+>["getTransactionStatus"] = async (account: Account, transaction: Transaction) => {
const errors: Record = {};
const warnings: Record = {};
const useAllAmount = !!transaction.useAllAmount;
diff --git a/libs/coin-modules/coin-bitcoin/src/hw-signMessage.test.ts b/libs/coin-modules/coin-bitcoin/src/hw-signMessage.test.ts
index f6137c4dcc94..169b05ebc19c 100644
--- a/libs/coin-modules/coin-bitcoin/src/hw-signMessage.test.ts
+++ b/libs/coin-modules/coin-bitcoin/src/hw-signMessage.test.ts
@@ -1,10 +1,7 @@
-import BigNumber from "bignumber.js";
-import { emptyHistoryCache } from "@ledgerhq/coin-framework/account/index";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
-import { listCryptoCurrencies } from "@ledgerhq/cryptoassets/index";
import { signMessage } from "./hw-signMessage";
import { BitcoinSigner } from "./signer";
-import { BitcoinAccount, BitcoinResources } from "./types";
+import { createFixtureAccount } from "./__tests__/fixtures/common.fixtures";
describe("signMessage", () => {
it("returns a base64 format string", async () => {
@@ -43,40 +40,3 @@ describe("signMessage", () => {
});
});
});
-
-function createFixtureAccount(account?: Partial): BitcoinAccount {
- const currency = listCryptoCurrencies(true).find(c => c.id === "bitcoin")!;
-
- const bitcoinResources: BitcoinResources = account?.bitcoinResources || {
- utxos: [],
- };
-
- const freshAddress = {
- address: "1fMK6i7CMDES1GNGDEMX5ddDaxbkjWPw1M",
- derivationPath: "derivation_path",
- };
-
- return {
- type: "Account",
- id: "E0A538D5-5EE7-4E37-BB57-F373B08B8580",
- seedIdentifier: "FD5EAFE3-8C7F-4565-ADFA-2A1A2067322A",
- derivationMode: "",
- index: 0,
- freshAddress: freshAddress.address,
- freshAddressPath: freshAddress.derivationPath,
- used: true,
- balance: account?.balance || new BigNumber(0),
- spendableBalance: account?.spendableBalance || new BigNumber(0),
- creationDate: new Date(),
- blockHeight: 100_000,
- currency,
- operationsCount: 0,
- operations: [],
- pendingOperations: [],
- lastSyncDate: new Date(),
- balanceHistoryCache: emptyHistoryCache,
- swapHistory: [],
-
- bitcoinResources,
- };
-}
diff --git a/libs/coin-modules/coin-bitcoin/src/logic.ts b/libs/coin-modules/coin-bitcoin/src/logic.ts
index 0fa700894075..ecbb61996f3d 100644
--- a/libs/coin-modules/coin-bitcoin/src/logic.ts
+++ b/libs/coin-modules/coin-bitcoin/src/logic.ts
@@ -19,7 +19,6 @@ import type { Account, Operation, OperationType } from "@ledgerhq/types-live";
const minFees: Partial> = {
bitcoin: 1000,
bitcoin_gold: 1000,
- pivx: 2000,
qtum: 4000,
stratis: 2000,
};
diff --git a/libs/coin-modules/coin-bitcoin/src/networks.ts b/libs/coin-modules/coin-bitcoin/src/networks.ts
index 3e0dcc340371..2b9947f8d38b 100644
--- a/libs/coin-modules/coin-bitcoin/src/networks.ts
+++ b/libs/coin-modules/coin-bitcoin/src/networks.ts
@@ -213,20 +213,6 @@ export const getNetworkParameters = (networkName: string): BitcoinLikeNetworkPar
sigHash: BitcoinLikeSigHashType.SIGHASH_ALL,
additionalBIPs: [],
};
- } else if (networkName === "pivx") {
- return {
- identifier: "pivx",
- P2PKHVersion: Buffer.from([0x1e]),
- P2SHVersion: Buffer.from([0x0d]),
- xpubVersion: Buffer.from([0x02, 0x2d, 0x25, 0x33]),
- feePolicy: BitcoinLikeFeePolicy.PER_BYTE,
- dustAmount: new BigNumber(10000),
- messagePrefix: "DarkNet Signed Message:\n",
- usesTimestampedTransaction: false,
- timestampDelay: new BigNumber(0),
- sigHash: BitcoinLikeSigHashType.SIGHASH_ALL,
- additionalBIPs: [],
- };
} else if (networkName === "clubcoin") {
return {
identifier: "club",
diff --git a/libs/coin-modules/coin-bitcoin/src/prepareTransaction.ts b/libs/coin-modules/coin-bitcoin/src/prepareTransaction.ts
index 3983ba414e6b..7d6b852c7747 100644
--- a/libs/coin-modules/coin-bitcoin/src/prepareTransaction.ts
+++ b/libs/coin-modules/coin-bitcoin/src/prepareTransaction.ts
@@ -18,13 +18,19 @@ export const prepareTransaction: AccountBridge["prepareTransaction"
const feePerByte = inferFeePerByte(transaction, networkInfo);
if (
- (transaction.networkInfo === networkInfo &&
- (feePerByte === transaction.feePerByte || feePerByte.eq(transaction.feePerByte || 0))) ||
- transaction.feesStrategy === "custom"
+ transaction.networkInfo === networkInfo &&
+ (feePerByte === transaction.feePerByte || feePerByte.eq(transaction.feePerByte || 0))
) {
// nothing changed
return transaction;
}
+ // if fees strategy is custom, we don't want to change the feePerByte but we still want to update the networkInfo
+ if (transaction.feesStrategy === "custom") {
+ return {
+ ...transaction,
+ networkInfo,
+ };
+ }
return {
...transaction,
diff --git a/libs/coin-modules/coin-bitcoin/src/specs.ts b/libs/coin-modules/coin-bitcoin/src/specs.ts
index 176fdf8104fa..581937355c74 100644
--- a/libs/coin-modules/coin-bitcoin/src/specs.ts
+++ b/libs/coin-modules/coin-bitcoin/src/specs.ts
@@ -394,20 +394,6 @@ const bitcoinCash: AppSpec = {
minViableAmount: genericMinimalAmount,
};
-const pivx: AppSpec = {
- name: "PivX",
- currency: getCryptoCurrencyById("pivx"),
- dependency: "Bitcoin Legacy",
- appQuery: {
- model: DeviceModelId.nanoS,
- appName: "PivX",
- appVersion: "2.1.0-rc",
- },
- genericDeviceAction: acceptTransaction,
- test: genericTest,
- mutations: bitcoinLikeMutations(),
- minViableAmount: genericMinimalAmount,
-};
const minQtum = parseCurrencyUnit(getCryptoCurrencyById("qtum").units[0], "0.001");
const qtum: AppSpec = {
name: "Qtum",
@@ -573,7 +559,6 @@ export default {
dogecoin,
komodo,
litecoin,
- pivx,
qtum,
zcash,
zencash,
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/fixtures/common.fixtures.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/fixtures/common.fixtures.ts
new file mode 100644
index 000000000000..fd4278224054
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/fixtures/common.fixtures.ts
@@ -0,0 +1,86 @@
+import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
+
+import { Account } from "../../account";
+import { ICrypto } from "../../crypto/types";
+import Xpub from "../../xpub";
+import BitcoinLikeStorage from "../../storage";
+import BitcoinLikeExplorer from "../../explorer";
+import { IStorage } from "../../storage/types";
+
+export const mockCrypto = {
+ getAddress: jest.fn(),
+ toOutputScript: jest.fn(),
+ toOpReturnOutputScript: jest.fn(),
+ network: {
+ name: "testnet",
+ },
+} as unknown as jest.Mocked;
+
+export const mockCryptoCurrency = {
+ type: "CryptoCurrency",
+ id: "bitcoin",
+ name: "Bitcoin",
+ family: "bitcoin",
+ coinType: 0,
+ scheme: "native_segwit",
+ units: [
+ {
+ name: "BTC",
+ code: "BTC",
+ magnitude: 8,
+ },
+ ],
+ explorerViews: [
+ {
+ tx: "https://blockchain.info/tx/{txid}",
+ address: "https://blockchain.info/address/{address}",
+ },
+ ],
+ ticker: "BTC",
+ explorerId: "btc",
+ color: "#FF0000",
+ managerAppName: "Bitcoin",
+} as CryptoCurrency;
+
+export const getMockAccount = (derivationMode: string) => {
+ const bitcoinCryptoCurrency = getCryptoCurrencyById("bitcoin");
+ const mockStorage = new BitcoinLikeStorage();
+
+ return {
+ params: {
+ xpub: "test-xpub",
+ path: "test-path",
+ index: 0,
+ currency: "bitcoin",
+ network: "mainnet",
+ derivationMode,
+ },
+ xpub: new Xpub({
+ storage: mockStorage,
+ explorer: new BitcoinLikeExplorer({ cryptoCurrency: bitcoinCryptoCurrency }),
+ crypto: mockCrypto,
+ xpub: "test-xpub",
+ derivationMode,
+ }),
+ } as Account;
+};
+
+export const mockStorage = {
+ addAddress: jest.fn(),
+ hasPendingTx: jest.fn().mockReturnValue(false),
+ removePendingTxs: jest.fn(),
+ appendTxs: jest.fn(),
+ hasTx: jest.fn().mockReturnValue(true),
+ getUniquesAddresses: jest.fn(),
+ getAddressUnspentUtxos: jest.fn().mockReturnValue([]),
+ getTx: jest.fn(),
+ getLastConfirmedTxBlock: jest.fn(),
+ removeTxs: jest.fn(),
+ getHighestBlockHeightAndHash: jest.fn(),
+ getLastUnconfirmedTx: jest.fn(),
+ export: jest.fn(),
+ load: jest.fn(),
+ exportSync: jest.fn(),
+ loadSync: jest.fn(),
+} as unknown as jest.Mocked;
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/utils.test.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/utils.test.ts
index 49421ba22e29..ab03e863f8fb 100644
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/utils.test.ts
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/utils.test.ts
@@ -140,7 +140,6 @@ describe("Unit tests for various utils functions", () => {
validateAddrs(["D8cMCRimfjwQ9E8jJvgUswt18WnZbCUAaW"], "dogecoin", true);
validateAddrs(["dgb1q7zjgqa23xzf602ljfrc94248a9u27xml08nhct"], "digibyte", true);
validateAddrs(["REnTkuvjsmfshAZ3vukYfuS3ZGvfUatqFc"], "komodo", true);
- validateAddrs(["DQ7F2iTQn6kUpyvietinaC3Cxje2m1ULjS"], "pivx", true);
validateAddrs(["zndVnjbrzRxvhPGRea4jgsfSWE1hXFja1dc"], "zencash", true);
validateAddrs(["Dso59DoPRkfATcZgHGgfh9mpku7taw9srAv"], "decred", true);
validateAddrs(["Dcck4QrFF5wuLzQpwxb5evhSRD7ZTsJZwuh"], "decred", true);
@@ -159,7 +158,6 @@ describe("Unit tests for various utils functions", () => {
validateAddrs(["D8cMCRimfjwQ9E8jJvgUswt18WnZbCUAaa"], "dogecoin", false);
validateAddrs(["dgb1q7zjgqa23xzf602ljfrc94248a9u27xml08nhcc"], "digibyte", false);
validateAddrs(["REnTkuvjsmfshAZ3vukYfuS3ZGvfUatqFF"], "komodo", false);
- validateAddrs(["DQ7F2iTQn6kUpyvietinaC3Cxje2m1ULjj"], "pivx", false);
validateAddrs(["zndVnjbrzRxvhPGRea4jgsfSWE1hXFja1dd"], "zencash", false);
validateAddrs(["Dso59DoPRkfATcZgHGgff9mpku7taw9srAv"], "decred", false);
validateAddrs(["Dcck4QrFF5wuLQzpwxb5evhSRD7ZTsJZwuh"], "decred", false);
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/wallet.unit.test.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/wallet.unit.test.ts
new file mode 100644
index 000000000000..edc064180900
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/wallet.unit.test.ts
@@ -0,0 +1,226 @@
+import BigNumber from "bignumber.js";
+
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
+
+import BitcoinLikeWallet from "../wallet";
+import { Account } from "../account";
+import Xpub from "../xpub";
+import { PickingStrategy } from "../pickingstrategies/types";
+import { TX, Address, Output } from "../storage/types";
+import { DerivationModes, TransactionInfo } from "../types";
+
+import { getMockAccount } from "./fixtures/common.fixtures";
+import { mockSigner } from "../../__tests__/fixtures/common.fixtures";
+
+jest.mock("../explorer");
+jest.mock("../crypto/factory");
+
+const DERIVATION_MODE = DerivationModes.TAPROOT;
+
+const bitcoinCryptoCurrency = getCryptoCurrencyById("bitcoin");
+
+describe("BitcoinLikeWallet", () => {
+ let wallet: BitcoinLikeWallet;
+ let mockAccount: Account;
+
+ beforeEach(() => {
+ wallet = new BitcoinLikeWallet();
+ mockAccount = getMockAccount(DERIVATION_MODE);
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test("generateAccount", async () => {
+ const params = {
+ xpub: "test-xpub",
+ path: "test-path",
+ index: 0,
+ currency: "bitcoin",
+ network: "mainnet",
+ derivationMode: DERIVATION_MODE,
+ } as const;
+
+ const account = await wallet.generateAccount(params, bitcoinCryptoCurrency);
+
+ expect(account.params).toEqual(params);
+ expect(account.xpub).toBeInstanceOf(Xpub);
+ });
+
+ test("syncAccount", async () => {
+ mockAccount.xpub.sync = jest.fn().mockResolvedValue(undefined);
+ });
+
+ test("syncAccount", async () => {
+ mockAccount.xpub.sync = jest.fn().mockResolvedValue(undefined);
+
+ await wallet.syncAccount(mockAccount, 1000);
+
+ expect(mockAccount.xpub.sync).toHaveBeenCalled();
+ expect(mockAccount.xpub.currentBlockHeight).toBe(1000);
+ expect(mockAccount.xpub.syncedBlockHeight).toBe(1000);
+ });
+
+ test("getAccountNewReceiveAddress", async () => {
+ const newAddress = { address: "new-receive-address", account: 0, index: 1 } as Address;
+ mockAccount.xpub.getNewAddress = jest.fn().mockResolvedValue(newAddress);
+
+ const address = await wallet.getAccountNewReceiveAddress(mockAccount);
+
+ expect(mockAccount.xpub.getNewAddress).toHaveBeenCalledWith(0, 1);
+ expect(address).toEqual(newAddress);
+ });
+
+ test("getAccountNewChangeAddress", async () => {
+ const newAddress = { address: "new-change-address", account: 1, index: 1 } as Address;
+ mockAccount.xpub.getNewAddress = jest.fn().mockResolvedValue(newAddress);
+
+ const address = await wallet.getAccountNewChangeAddress(mockAccount);
+
+ expect(mockAccount.xpub.getNewAddress).toHaveBeenCalledWith(1, 1);
+ expect(address).toEqual(newAddress);
+ });
+
+ test("getAccountTransactions", async () => {
+ const txs = { txs: [{ hash: "tx1" }, { hash: "tx2" }] as TX[] };
+ mockAccount.xpub.storage.export = jest.fn().mockResolvedValue(txs);
+
+ const transactions = await wallet.getAccountTransactions(mockAccount);
+
+ expect(mockAccount.xpub.storage.export).toHaveBeenCalled();
+ expect(transactions).toEqual(txs);
+ });
+
+ test("getAccountUnspentUtxos", async () => {
+ const addresses = [{ address: "address1", account: 0, index: 0 }] as Address[];
+ const utxos = [{ value: "10" }] as Output[];
+ mockAccount.xpub.getXpubAddresses = jest.fn().mockResolvedValue(addresses);
+ mockAccount.xpub.storage.getAddressUnspentUtxos = jest.fn().mockResolvedValue(utxos);
+
+ const unspentUtxos = await wallet.getAccountUnspentUtxos(mockAccount);
+
+ expect(mockAccount.xpub.getXpubAddresses).toHaveBeenCalled();
+ expect(mockAccount.xpub.storage.getAddressUnspentUtxos).toHaveBeenCalledWith(addresses[0]);
+ expect(unspentUtxos).toEqual(utxos);
+ });
+
+ test("estimateAccountMaxSpendable", async () => {
+ const addresses = [{ address: "address1", account: 0, index: 0 }] as Address[];
+ const utxos = [
+ {
+ value: "500",
+ address: "address1",
+ output_hash: "hash1",
+ output_index: 0,
+ block_height: 1000,
+ },
+ {
+ value: "200",
+ address: "address2",
+ output_hash: "hash2",
+ output_index: 1,
+ block_height: null,
+ },
+ ] as Output[];
+ mockAccount.xpub.getXpubAddresses = jest.fn().mockResolvedValue(addresses);
+ mockAccount.xpub.getAccountAddresses = jest
+ .fn()
+ .mockResolvedValue([{ address: "address2", account: 1, index: 1 }] as Address[]);
+ mockAccount.xpub.storage.getAddressUnspentUtxos = jest.fn().mockResolvedValue(utxos);
+ mockAccount.xpub.crypto.toOutputScript = jest
+ .fn()
+ .mockReturnValue(Buffer.from("output-script"));
+ mockAccount.xpub.crypto.toOpReturnOutputScript = jest
+ .fn()
+ .mockReturnValue(Buffer.from("op-return-script"));
+
+ const maxSpendable = await wallet.estimateAccountMaxSpendable(mockAccount, 1, []);
+
+ expect(mockAccount.xpub.getXpubAddresses).toHaveBeenCalled();
+ expect(mockAccount.xpub.getAccountAddresses).toHaveBeenCalledWith(1);
+ expect(maxSpendable.toNumber()).toBeGreaterThan(0);
+ });
+
+ test("getAccountBalance", async () => {
+ const balance = new BigNumber(100);
+ mockAccount.xpub.getXpubBalance = jest.fn().mockResolvedValue(balance);
+
+ const accountBalance = await wallet.getAccountBalance(mockAccount);
+
+ expect(mockAccount.xpub.getXpubBalance).toHaveBeenCalled();
+ expect(accountBalance).toEqual(balance);
+ });
+
+ test("getAccountPendings", async () => {
+ const addresses = [{ address: "address1", account: 0, index: 0 }] as Address[];
+ const pendings = [{ hash: "pending1" }, { hash: "pending2" }] as TX[];
+ mockAccount.xpub.getXpubAddresses = jest.fn().mockResolvedValue(addresses);
+ mockAccount.xpub.explorer.getPendings = jest.fn().mockResolvedValue(pendings);
+
+ const pendingTxs = await wallet.getAccountPendings(mockAccount);
+
+ expect(mockAccount.xpub.getXpubAddresses).toHaveBeenCalled();
+ expect(mockAccount.xpub.explorer.getPendings).toHaveBeenCalledWith({
+ account: 0,
+ address: "address1",
+ index: 0,
+ });
+ expect(pendingTxs).toEqual(pendings);
+ });
+
+ test("buildAccountTx", async () => {
+ const txInfo = {
+ inputs: [],
+ outputs: [],
+ fee: 0,
+ associatedDerivations: [],
+ changeAddress: { address: "change-address", account: 1, index: 1 },
+ } as TransactionInfo;
+ mockAccount.xpub.buildTx = jest.fn().mockResolvedValue(txInfo);
+ mockAccount.xpub.getNewAddress = jest
+ .fn()
+ .mockResolvedValue({ address: "change-address", account: 1, index: 1 } as Address);
+
+ const params = {
+ fromAccount: mockAccount,
+ dest: "destination-address",
+ amount: new BigNumber(10),
+ feePerByte: 1,
+ utxoPickingStrategy: {} as PickingStrategy,
+ sequence: 0,
+ };
+
+ const transactionInfo = await wallet.buildAccountTx(params);
+
+ expect(mockAccount.xpub.getNewAddress).toHaveBeenCalledWith(1, 1);
+ expect(mockAccount.xpub.buildTx).toHaveBeenCalledWith({
+ destAddress: params.dest,
+ amount: params.amount,
+ feePerByte: params.feePerByte,
+ changeAddress: { address: "change-address", account: 1, index: 1 },
+ utxoPickingStrategy: params.utxoPickingStrategy,
+ sequence: params.sequence,
+ opReturnData: undefined,
+ });
+ expect(transactionInfo).toEqual(txInfo);
+ });
+
+ it("should return the signature", async () => {
+ const txInfo = {
+ inputs: [],
+ outputs: [],
+ fee: 0,
+ associatedDerivations: [],
+ changeAddress: { address: "change-address", account: 1, index: 1 },
+ } as TransactionInfo;
+
+ const signature = await wallet.signAccountTx({
+ btc: mockSigner,
+ fromAccount: mockAccount,
+ txInfo,
+ });
+
+ expect(signature).toBe("createPaymentTransactionReturn");
+ });
+});
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.syncing.integration.test.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.syncing.integration.test.ts
index ec0fec651061..ba782139e043 100644
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.syncing.integration.test.ts
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.syncing.integration.test.ts
@@ -126,14 +126,6 @@ describe("xpub integration sync", () => {
network: coininfo.bitcoin.main.toBitcoinJS(),
currencyId: "komodo",
},
- {
- xpub: "ToEA6kVVodfRW2DuuMjPPMsLLukY4EsScxdHYJkTtdopPD5Z5t9gpB2zEwpschy7rFzTqxQCXQFUBnxT5MAnfkNT4dkWqtHPE2L7bG7GC24XnLy",
- derivationMode: DerivationModes.LEGACY,
- addresses: 1,
- balance: 400000000,
- network: coininfo.bitcoin.main.toBitcoinJS(),
- currencyId: "pivx",
- },
{
xpub: "dpubZFUiMExUREbqJQVJkfXSs4wjUb1jwVkoofnPK8Mt95j3PanCyq9Mc4aFnWtRZkhci9ZYPVLZybVLMMkS6g1nKBTN4899KJwGeVBvyumvcjW",
derivationMode: DerivationModes.LEGACY,
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.unit.test.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.unit.test.ts
new file mode 100644
index 000000000000..f315ec07dbce
--- /dev/null
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/__tests__/xpub.unit.test.ts
@@ -0,0 +1,172 @@
+import { BigNumber } from "bignumber.js";
+
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
+
+import Xpub from "../xpub";
+import { Output } from "../storage/types";
+import { DerivationModes } from "../types";
+import BitcoinLikeExplorer from "../explorer";
+
+import { mockCrypto, mockStorage } from "./fixtures/common.fixtures";
+
+jest.mock("../utils", () => ({
+ ...jest.requireActual("../utils"),
+ computeDustAmount: jest.fn().mockReturnValue(50),
+}));
+
+describe("Xpub", () => {
+ let xpub: Xpub;
+ const DERIVATION_MODE = DerivationModes.TAPROOT;
+ const bitcoinCryptoCurrency = getCryptoCurrencyById("bitcoin");
+ const mockExplorer = new BitcoinLikeExplorer({ cryptoCurrency: bitcoinCryptoCurrency });
+
+ beforeEach(() => {
+ xpub = new Xpub({
+ storage: mockStorage,
+ explorer: mockExplorer,
+ crypto: mockCrypto,
+ xpub: "test-xpub",
+ derivationMode: DERIVATION_MODE,
+ });
+ });
+
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
+ test("syncAddress", async () => {
+ mockCrypto.getAddress.mockResolvedValue("address1");
+ mockStorage.hasPendingTx.mockReturnValue(false);
+ mockStorage.hasTx.mockReturnValue(true);
+
+ const result = await xpub.syncAddress(0, 0, false);
+
+ expect(mockCrypto.getAddress).toHaveBeenCalledWith(DERIVATION_MODE, "test-xpub", 0, 0);
+ expect(mockStorage.addAddress).toHaveBeenCalled();
+ expect(mockStorage.hasPendingTx).toHaveBeenCalled();
+ expect(mockStorage.hasTx).toHaveBeenCalled();
+ expect(result).toBe(true);
+ });
+
+ test("checkAddressesBlock", async () => {
+ jest.spyOn(xpub, "syncAddress").mockResolvedValue(true);
+
+ const result = await xpub.checkAddressesBlock(0, 0, false);
+
+ expect(xpub.syncAddress).toHaveBeenCalledTimes(xpub.GAP);
+ expect(result).toBe(true);
+ });
+
+ test("syncAccount", async () => {
+ jest
+ .spyOn(xpub, "checkAddressesBlock")
+ .mockResolvedValueOnce(true)
+ .mockResolvedValueOnce(false);
+
+ const result = await xpub.syncAccount(0, false);
+
+ expect(xpub.checkAddressesBlock).toHaveBeenCalled();
+ expect(result).toBe(xpub.GAP);
+ });
+
+ test("sync", async () => {
+ mockStorage.getHighestBlockHeightAndHash.mockReturnValue(null);
+ jest.spyOn(xpub, "syncAccount").mockResolvedValue(0);
+ mockCrypto.getAddress.mockResolvedValue("fresh-address");
+
+ await xpub.sync();
+
+ expect(mockStorage.getHighestBlockHeightAndHash).toHaveBeenCalled();
+ expect(xpub.syncAccount).toHaveBeenCalledTimes(2);
+ expect(mockCrypto.getAddress).toHaveBeenCalledWith(DERIVATION_MODE, "test-xpub", 0, 0);
+ expect(xpub.freshAddress).toBe("fresh-address");
+ });
+
+ test("getXpubBalance", async () => {
+ const addresses = [{ address: "address1", account: 0, index: 0 }];
+ jest.spyOn(xpub, "getXpubAddresses").mockResolvedValue(addresses);
+ jest.spyOn(xpub, "getAddressesBalance").mockResolvedValue(new BigNumber(100));
+
+ const balance = await xpub.getXpubBalance();
+
+ expect(xpub.getXpubAddresses).toHaveBeenCalled();
+ expect(xpub.getAddressesBalance).toHaveBeenCalledWith(addresses);
+ expect(balance.toNumber()).toBe(100);
+ });
+
+ test("getAccountBalance", async () => {
+ const addresses = [{ address: "address1", account: 0, index: 0 }];
+ jest.spyOn(xpub, "getAccountAddresses").mockResolvedValue(addresses);
+ jest.spyOn(xpub, "getAddressesBalance").mockResolvedValue(new BigNumber(50));
+
+ const balance = await xpub.getAccountBalance(0);
+
+ expect(xpub.getAccountAddresses).toHaveBeenCalledWith(0);
+ expect(xpub.getAddressesBalance).toHaveBeenCalledWith(addresses);
+ expect(balance.toNumber()).toBe(50);
+ });
+
+ test("getAddressBalance", async () => {
+ const address = { address: "address1", account: 0, index: 0 };
+ const unspentUtxos: Output[] = [
+ { value: "30", address: "", output_hash: "", output_index: 0, block_height: 0, rbf: false },
+ { value: "20", address: "", output_hash: "", output_index: 0, block_height: 0, rbf: false },
+ ];
+ mockStorage.getAddressUnspentUtxos.mockReturnValue(unspentUtxos);
+
+ const balance = await xpub.getAddressBalance(address);
+
+ expect(mockStorage.getAddressUnspentUtxos).toHaveBeenCalledWith(address);
+ expect(balance.toNumber()).toBe(50);
+ });
+
+ test("getNewAddress", async () => {
+ const accountAddresses = [{ address: "address1", account: 0, index: 0 }];
+ jest.spyOn(xpub, "getAccountAddresses").mockResolvedValue(accountAddresses);
+ mockCrypto.getAddress.mockResolvedValue("new-address");
+
+ const newAddress = await xpub.getNewAddress(0, 1);
+
+ expect(xpub.getAccountAddresses).toHaveBeenCalledWith(0);
+ expect(mockCrypto.getAddress).toHaveBeenCalledWith(DERIVATION_MODE, "test-xpub", 0, 1);
+ expect(newAddress.address).toBe("new-address");
+ expect(newAddress.index).toBe(1);
+ });
+
+ it("should build transaction correctly", async () => {
+ mockCrypto.toOutputScript = jest.fn().mockReturnValue("outputScript");
+ mockExplorer.getTxHex = jest.fn().mockResolvedValue("txHex");
+ mockStorage.getTx = jest.fn().mockResolvedValue({ account: 0, index: 0 });
+
+ const tx = await xpub.buildTx({
+ destAddress: "destinationAddress",
+ amount: new BigNumber(1000),
+ feePerByte: 1,
+ changeAddress: { address: "changeAddress", account: 0, index: 0 },
+ utxoPickingStrategy: {
+ crypto: mockCrypto,
+ derivationMode: DERIVATION_MODE,
+ excludedUTXOs: [],
+ selectUnspentUtxosToUse: jest.fn().mockResolvedValue({
+ totalValue: new BigNumber(2000),
+ unspentUtxos: [
+ {
+ output_hash: "hash2",
+ value: new BigNumber(1500),
+ address: "address1",
+ output_index: 0,
+ },
+ ],
+ fee: new BigNumber(100),
+ needChangeoutput: true,
+ }),
+ },
+ sequence: 0,
+ opReturnData: undefined,
+ });
+
+ expect(tx.inputs.length).toBe(1);
+ expect(tx.outputs.length).toBe(2); // one for destAddres, one for change
+ expect(tx.fee).toBe(100);
+ });
+});
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/factory.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/factory.ts
index 7b4e5e50dafe..416a1d43ae50 100644
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/factory.ts
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/factory.ts
@@ -55,11 +55,6 @@ export default function cryptoFactory(currency: Currency): ICrypto {
res = new crypto.Komodo({ network });
break;
}
- case "pivx": {
- const network = coininfo.bitcoin.main.toBitcoinJS();
- res = new crypto.Pivx({ network });
- break;
- }
case "zencash": {
const network = coininfo.zcash.main.toBitcoinJS();
res = new crypto.Zen({ network });
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/index.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/index.ts
index f29c64250894..aadafc82649b 100644
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/index.ts
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/index.ts
@@ -6,7 +6,6 @@ export { default as Zec } from "./zec";
export { default as Zen } from "./zen";
export { default as Dash } from "./dash";
export { default as Komodo } from "./komodo";
-export { default as Pivx } from "./pivx";
export { default as BitcoinGold } from "./bitcoingold";
export { default as Doge } from "./doge";
export { default as Qtum } from "./qtum";
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/pivx.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/pivx.ts
deleted file mode 100644
index 151a532a2997..000000000000
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/pivx.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import Base from "./base";
-
-class Pivx extends Base {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
- constructor({ network }: { network: any }) {
- super({ network });
- // refer to https://github.com/LedgerHQ/lib-ledger-core/blob/master/core/src/wallet/bitcoin/networks.cpp#L369
- this.network.bip32.public = 0x022d2533;
- this.network.pubKeyHash = 0x1e;
- this.network.scriptHash = 0x0d;
- this.network.dustThreshold = 10000;
- this.network.dustPolicy = "FIXED";
- this.network.usesTimestampedTransaction = false;
- }
-}
-
-export default Pivx;
diff --git a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/types.ts b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/types.ts
index 3ea1b6ee18d1..5faac0358694 100644
--- a/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/types.ts
+++ b/libs/coin-modules/coin-bitcoin/src/wallet-btc/crypto/types.ts
@@ -25,7 +25,6 @@ export type Currency =
| "dogecoin"
| "digibyte"
| "komodo"
- | "pivx"
| "zencash"
| "decred"
| "bitcoin_testnet";
diff --git a/libs/coin-modules/coin-cardano/CHANGELOG.md b/libs/coin-modules/coin-cardano/CHANGELOG.md
index 058db8492d4d..6c81f5704239 100644
--- a/libs/coin-modules/coin-cardano/CHANGELOG.md
+++ b/libs/coin-modules/coin-cardano/CHANGELOG.md
@@ -1,5 +1,41 @@
# @ledgerhq/coin-cardano
+## 0.2.0
+
+### Minor Changes
+
+- [#7213](https://github.com/LedgerHQ/ledger-live/pull/7213) [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008) Thanks [@pavanvora](https://github.com/pavanvora)! - Add babbage support to Cardano with typhonjs v2
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.2.0-next.0
+
+### Minor Changes
+
+- [#7213](https://github.com/LedgerHQ/ledger-live/pull/7213) [`354d913`](https://github.com/LedgerHQ/ledger-live/commit/354d9138a4bd9b54001ff1330a8000ee94aea008) Thanks [@pavanvora](https://github.com/pavanvora)! - Add babbage support to Cardano with typhonjs v2
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.1.4
### Patch Changes
diff --git a/libs/coin-modules/coin-cardano/package.json b/libs/coin-modules/coin-cardano/package.json
index 3a9bd2365864..aacac22427a5 100644
--- a/libs/coin-modules/coin-cardano/package.json
+++ b/libs/coin-modules/coin-cardano/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-cardano",
- "version": "0.1.4",
+ "version": "0.2.0",
"description": "Ledger Cardano Coin integration",
"keywords": [
"Ledger",
@@ -61,7 +61,7 @@
"@ledgerhq/types-cryptoassets": "workspace:^",
"@ledgerhq/types-live": "workspace:^",
"@stricahq/bip32ed25519": "^1.0.3",
- "@stricahq/typhonjs": "^1.2.6",
+ "@stricahq/typhonjs": "^2.0.0",
"bech32": "^1.1.3",
"bignumber.js": "^9.1.2",
"expect": "^27.4.6",
diff --git a/libs/coin-modules/coin-cardano/src/api/getNetworkInfo.ts b/libs/coin-modules/coin-cardano/src/api/getNetworkInfo.ts
index bc7ee8d3d376..c25df81ec4aa 100644
--- a/libs/coin-modules/coin-cardano/src/api/getNetworkInfo.ts
+++ b/libs/coin-modules/coin-cardano/src/api/getNetworkInfo.ts
@@ -1,11 +1,10 @@
import network from "@ledgerhq/live-network/network";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
import { CARDANO_API_ENDPOINT, CARDANO_TESTNET_API_ENDPOINT } from "../constants";
-import { getEpoch, isTestnet } from "../logic";
-import { CardanoAccount } from "../types";
+import { isTestnet } from "../logic";
import { APINetworkInfo } from "./api-types";
-async function fetchNetworkInfo(currency: CryptoCurrency): Promise {
+export async function fetchNetworkInfo(currency: CryptoCurrency): Promise {
const res = await network({
method: "GET",
url: isTestnet(currency)
@@ -14,21 +13,3 @@ async function fetchNetworkInfo(currency: CryptoCurrency): Promise {
- if (a && a.cardanoResources) {
- const currencyId = a.currency.id;
- const currentEpoch = getEpoch(currencyId, new Date());
- const lastSyncedEpoch = getEpoch(currencyId, a.lastSyncDate);
-
- if (currentEpoch === lastSyncedEpoch) {
- return {
- protocolParams: a.cardanoResources.protocolParams,
- };
- }
- }
- return fetchNetworkInfo(currency);
-}
diff --git a/libs/coin-modules/coin-cardano/src/buildOptimisticOperation.ts b/libs/coin-modules/coin-cardano/src/buildOptimisticOperation.ts
index 4212035f33d7..2904f79f011f 100644
--- a/libs/coin-modules/coin-cardano/src/buildOptimisticOperation.ts
+++ b/libs/coin-modules/coin-cardano/src/buildOptimisticOperation.ts
@@ -33,7 +33,9 @@ export const buildOptimisticOperation = (
.getInputs()
.reduce(
(total, i) =>
- accountCreds.has(i.address.paymentCredential.hash) ? total.plus(i.amount) : total.plus(0),
+ accountCreds.has(i.address.paymentCredential.hash.toString("hex"))
+ ? total.plus(i.amount)
+ : total.plus(0),
new BigNumber(0),
);
@@ -42,7 +44,7 @@ export const buildOptimisticOperation = (
.reduce(
(total, o) =>
o.address instanceof ShelleyTypeAddress &&
- accountCreds.has(o.address.paymentCredential.hash)
+ accountCreds.has(o.address.paymentCredential.hash.toString("hex"))
? total.plus(o.amount)
: total.plus(0),
new BigNumber(0),
@@ -76,7 +78,7 @@ export const buildOptimisticOperation = (
const walletRegistration = stakeRegistrationCertificates.find(
c =>
c.stakeCredential.type === HashType.ADDRESS &&
- c.stakeCredential.hash === stakeCredential.key,
+ c.stakeCredential.hash.toString("hex") === stakeCredential.key,
);
if (walletRegistration) {
extra.deposit = formatCurrencyUnit(
@@ -94,7 +96,7 @@ export const buildOptimisticOperation = (
const walletDeRegistration = stakeDeRegistrationCertificates.find(
c =>
c.stakeCredential.type === HashType.ADDRESS &&
- c.stakeCredential.hash === stakeCredential.key,
+ c.stakeCredential.hash.toString("hex") === stakeCredential.key,
);
if (walletDeRegistration) {
operationValue = operationValue.minus(protocolParams.stakeKeyDeposit);
@@ -113,7 +115,7 @@ export const buildOptimisticOperation = (
const walletWithdraw = txWithdrawals.find(
w =>
w.rewardAccount.stakeCredential.type === HashType.ADDRESS &&
- w.rewardAccount.stakeCredential.hash === stakeCredential.key,
+ w.rewardAccount.stakeCredential.hash.toString("hex") === stakeCredential.key,
);
if (walletWithdraw) {
operationValue = operationValue.minus(walletWithdraw.amount);
diff --git a/libs/coin-modules/coin-cardano/src/buildSubAccounts.ts b/libs/coin-modules/coin-cardano/src/buildSubAccounts.ts
index f80ac20b5025..100955c4a864 100644
--- a/libs/coin-modules/coin-cardano/src/buildSubAccounts.ts
+++ b/libs/coin-modules/coin-cardano/src/buildSubAccounts.ts
@@ -90,10 +90,14 @@ const mapTxToTokenAccountOperation = ({
fee: new BigNumber(tx.fees),
value: token.amount.absoluteValue(),
senders: tx.inputs.map(i =>
- isHexString(i.address) ? TyphonUtils.getAddressFromHex(i.address).getBech32() : i.address,
+ isHexString(i.address)
+ ? TyphonUtils.getAddressFromHex(Buffer.from(i.address, "hex")).getBech32()
+ : i.address,
),
recipients: tx.outputs.map(o =>
- isHexString(o.address) ? TyphonUtils.getAddressFromHex(o.address).getBech32() : o.address,
+ isHexString(o.address)
+ ? TyphonUtils.getAddressFromHex(Buffer.from(o.address, "hex")).getBech32()
+ : o.address,
),
blockHeight: tx.blockHeight,
date: new Date(tx.timestamp),
diff --git a/libs/coin-modules/coin-cardano/src/buildTransaction.ts b/libs/coin-modules/coin-cardano/src/buildTransaction.ts
index 6830d7c1a788..7e246b280a04 100644
--- a/libs/coin-modules/coin-cardano/src/buildTransaction.ts
+++ b/libs/coin-modules/coin-cardano/src/buildTransaction.ts
@@ -17,9 +17,12 @@ import {
Token,
Transaction,
} from "./types";
+import { CARDANO_MAX_SUPPLY } from "./constants";
function getTyphonInputFromUtxo(utxo: CardanoOutput): TyphonTypes.Input {
- const address = TyphonUtils.getAddressFromHex(utxo.address) as TyphonTypes.ShelleyAddress;
+ const address = TyphonUtils.getAddressFromHex(
+ Buffer.from(utxo.address, "hex"),
+ ) as TyphonTypes.ShelleyAddress;
if (address.paymentCredential.type === TyphonTypes.HashType.ADDRESS) {
address.paymentCredential.bipPath = utxo.paymentCredential.path;
}
@@ -40,7 +43,7 @@ function getRewardWithdrawalCertificate(account: CardanoAccount): TyphonTypes.Wi
const stakeCredential = getAccountStakeCredential(account.xpub as string, account.index);
const stakeKeyHashCredential: TyphonTypes.HashCredential = {
- hash: stakeCredential.key,
+ hash: Buffer.from(stakeCredential.key, "hex"),
type: TyphonTypes.HashType.ADDRESS,
bipPath: stakeCredential.path,
};
@@ -107,9 +110,13 @@ const buildSendTokenTransaction = async ({
});
const totalAddedTokenAmount = new BigNumber(0);
- const requiredMinAdaForTokens = TyphonUtils.calculateMinUtxoAmount(
- tokensToSend,
- new BigNumber(cardanoResources.protocolParams.lovelacePerUtxoWord),
+ const requiredMinAdaForTokens = TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: receiverAddress,
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokensToSend,
+ },
+ new BigNumber(cardanoResources.protocolParams.utxoCostPerByte),
);
// Add enough utxo to cover token amount
for (let i = 0; i < sortedTokenUtxo.length; i++) {
@@ -170,14 +177,17 @@ const buildSendAdaTransaction = async ({
// if account holds any tokens then add it to changeAddress,
// with minimum required ADA to spend those tokens
if (tokenBalance.length) {
- const minAmountToSpendTokens = TyphonUtils.calculateMinUtxoAmount(
- tokenBalance,
- new BigNumber(protocolParams.lovelacePerUtxoWord),
- false,
+ const minAmountForChangeTokens = TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: changeAddress,
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokenBalance,
+ },
+ new BigNumber(protocolParams.utxoCostPerByte),
);
typhonTx.addOutput({
address: changeAddress,
- amount: minAmountToSpendTokens,
+ amount: minAmountForChangeTokens,
tokens: tokenBalance,
});
}
@@ -239,7 +249,7 @@ const buildDelegateTransaction = async ({
const stakeCredential = getAccountStakeCredential(account.xpub as string, account.index);
const stakeKeyHashCredential: TyphonTypes.HashCredential = {
- hash: stakeCredential.key,
+ hash: Buffer.from(stakeCredential.key, "hex"),
type: TyphonTypes.HashType.ADDRESS,
bipPath: stakeCredential.path,
};
@@ -301,7 +311,7 @@ const buildUndelegateTransaction = async ({
const stakeCredential = getAccountStakeCredential(account.xpub as string, account.index);
const stakeKeyHashCredential: TyphonTypes.HashCredential = {
- hash: stakeCredential.key,
+ hash: Buffer.from(stakeCredential.key, "hex"),
type: TyphonTypes.HashType.ADDRESS,
bipPath: stakeCredential.path,
};
@@ -367,6 +377,9 @@ export const buildTransaction = async (
priceSteps: new BigNumber(protocolParams.priceSteps),
priceMem: new BigNumber(protocolParams.priceMem),
languageView: protocolParams.languageView,
+ maxTxSize: Number(protocolParams.maxTxSize),
+ maxValueSize: Number(protocolParams.maxValueSize),
+ utxoCostPerByte: new BigNumber(protocolParams.utxoCostPerByte),
},
});
const ttl = getTTL(account.currency.id);
@@ -395,7 +408,7 @@ export const buildTransaction = async (
});
if (transaction.mode === "send") {
- const receiverAddress = TyphonUtils.getAddressFromBech32(transaction.recipient);
+ const receiverAddress = TyphonUtils.getAddressFromString(transaction.recipient);
if (transaction.subAccountId) {
// Token Transaction
const tokenAccount = account.subAccounts
diff --git a/libs/coin-modules/coin-cardano/src/constants.ts b/libs/coin-modules/coin-cardano/src/constants.ts
index 0c17535f258c..e3ab7bbca4f4 100644
--- a/libs/coin-modules/coin-cardano/src/constants.ts
+++ b/libs/coin-modules/coin-cardano/src/constants.ts
@@ -5,6 +5,7 @@ export const TTL_GAP = 7200;
export const CARDANO_PURPOSE = 1852;
export const CARDANO_COIN_TYPE = 1815;
export const MEMO_LABEL = 674;
+export const CARDANO_MAX_SUPPLY = 45e9;
export const CARDANO_API_ENDPOINT = getEnv("CARDANO_API_ENDPOINT");
export const CARDANO_TESTNET_API_ENDPOINT = getEnv("CARDANO_TESTNET_API_ENDPOINT");
diff --git a/libs/coin-modules/coin-cardano/src/deviceTransactionConfig.ts b/libs/coin-modules/coin-cardano/src/deviceTransactionConfig.ts
index d6036fa248f4..84775707925e 100644
--- a/libs/coin-modules/coin-cardano/src/deviceTransactionConfig.ts
+++ b/libs/coin-modules/coin-cardano/src/deviceTransactionConfig.ts
@@ -12,6 +12,7 @@ import {
getBech32PoolId,
getBipPathString,
} from "./logic";
+import { CARDANO_MAX_SUPPLY } from "./constants";
function getDeviceTransactionConfig({
account,
@@ -54,9 +55,14 @@ function getDeviceTransactionConfig({
},
];
- const requiredMinAdaForTokens = TyphonUtils.calculateMinUtxoAmount(
- tokensToSend,
- new BigNumber(cardanoResources.protocolParams.lovelacePerUtxoWord),
+ const recipient = TyphonUtils.getAddressFromString(transaction.recipient);
+ const requiredMinAdaForTokens = TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: recipient,
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokensToSend,
+ },
+ new BigNumber(cardanoResources.protocolParams.utxoCostPerByte),
);
fields.push({
type: "text",
diff --git a/libs/coin-modules/coin-cardano/src/getTransactionStatus.ts b/libs/coin-modules/coin-cardano/src/getTransactionStatus.ts
index 9c24434be582..625c86bace4e 100644
--- a/libs/coin-modules/coin-cardano/src/getTransactionStatus.ts
+++ b/libs/coin-modules/coin-cardano/src/getTransactionStatus.ts
@@ -27,6 +27,7 @@ import type {
Transaction,
TransactionStatus,
} from "./types";
+import { CARDANO_MAX_SUPPLY } from "./constants";
export const getTransactionStatus: AccountBridge<
Transaction,
@@ -84,7 +85,8 @@ async function getSendTransactionStatus(
: undefined;
let tokensToSend: Array = [];
- if (transaction.subAccountId) {
+ const isTokenTx = !!transaction.subAccountId;
+ if (isTokenTx) {
// Token transaction
if (!tokenAccount || tokenAccount.type !== "TokenAccount") {
throw new Error("TokenAccount not found");
@@ -108,11 +110,7 @@ async function getSendTransactionStatus(
totalSpent = amount.plus(estimatedFees);
}
- const minTransactionAmount = TyphonUtils.calculateMinUtxoAmount(
- tokensToSend,
- new BigNumber(cardanoResources.protocolParams.lovelacePerUtxoWord),
- false,
- );
+ let minTransactionAmount = new BigNumber(0);
if (!transaction.fees) {
errors.fees = new FeeNotLoaded();
@@ -124,11 +122,22 @@ async function getSendTransactionStatus(
errors.recipient = new InvalidAddress("", {
currencyName: account.currency.name,
});
+ } else {
+ // minTransactionAmount can only be calculated with valid recipient
+ const recipient = TyphonUtils.getAddressFromString(transaction.recipient);
+ minTransactionAmount = TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: recipient,
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokensToSend,
+ },
+ new BigNumber(cardanoResources.protocolParams.utxoCostPerByte),
+ );
}
if (!amount.gt(0)) {
errors.amount = useAllAmount ? new CardanoNotEnoughFunds() : new AmountRequired();
- } else if (!transaction.subAccountId && amount.lt(minTransactionAmount)) {
+ } else if (!isTokenTx && amount.lt(minTransactionAmount)) {
errors.amount = new CardanoMinAmountError("", {
amount: minTransactionAmount.div(1e6).toString(),
});
diff --git a/libs/coin-modules/coin-cardano/src/hw-getAddress.ts b/libs/coin-modules/coin-cardano/src/hw-getAddress.ts
index dca0f44b9e20..7958e7f690f5 100644
--- a/libs/coin-modules/coin-cardano/src/hw-getAddress.ts
+++ b/libs/coin-modules/coin-cardano/src/hw-getAddress.ts
@@ -23,12 +23,14 @@ const resolver = (signerContext: SignerContext): GetAddressFn =>
signer.getAddress({ path, stakingPathString, networkParams, verify }),
);
- const address = TyphonUtils.getAddressFromHex(r.addressHex) as TyphonAddress.BaseAddress;
+ const address = TyphonUtils.getAddressFromHex(
+ Buffer.from(r.addressHex, "hex"),
+ ) as TyphonAddress.BaseAddress;
return {
address: address.getBech32(),
// Here, we use publicKey hash, as cardano app doesn't export the public key
- publicKey: address.paymentCredential.hash,
+ publicKey: address.paymentCredential.hash.toString("hex"),
path,
};
};
diff --git a/libs/coin-modules/coin-cardano/src/logic.ts b/libs/coin-modules/coin-cardano/src/logic.ts
index 1047943985cc..2e886e5d4a30 100644
--- a/libs/coin-modules/coin-cardano/src/logic.ts
+++ b/libs/coin-modules/coin-cardano/src/logic.ts
@@ -131,13 +131,13 @@ export function getBaseAddress({
stakeCred: StakeCredential;
}): TyphonAddress.BaseAddress {
const paymentCredential: TyphonTypes.HashCredential = {
- hash: paymentCred.key,
+ hash: Buffer.from(paymentCred.key, "hex"),
type: TyphonTypes.HashType.ADDRESS,
bipPath: paymentCred.path,
};
const stakeCredential: TyphonTypes.HashCredential = {
- hash: stakeCred.key,
+ hash: Buffer.from(stakeCred.key, "hex"),
type: TyphonTypes.HashType.ADDRESS,
bipPath: stakeCred.path,
};
@@ -153,7 +153,7 @@ export const isValidAddress = (address: string, networkId: number): boolean => {
if (!address) return false;
try {
- const cardanoAddress = TyphonUtils.getAddressFromBech32(address);
+ const cardanoAddress = TyphonUtils.getAddressFromString(address);
if (cardanoAddress instanceof ShelleyTypeAddress) {
const addressNetworkId = Number(cardanoAddress.getHex().toLowerCase().charAt(1));
if (addressNetworkId !== networkId) {
diff --git a/libs/coin-modules/coin-cardano/src/serialization.ts b/libs/coin-modules/coin-cardano/src/serialization.ts
index b0c993c3e951..993dbff8c404 100644
--- a/libs/coin-modules/coin-cardano/src/serialization.ts
+++ b/libs/coin-modules/coin-cardano/src/serialization.ts
@@ -115,6 +115,9 @@ function toProtocolParamsRaw({
collateralPercent,
priceSteps,
priceMem,
+ maxTxSize,
+ maxValueSize,
+ utxoCostPerByte,
languageView,
}: ProtocolParams): ProtocolParamsRaw {
return {
@@ -125,6 +128,9 @@ function toProtocolParamsRaw({
collateralPercent,
priceSteps,
priceMem,
+ maxTxSize,
+ maxValueSize,
+ utxoCostPerByte,
languageView,
};
}
@@ -137,6 +143,9 @@ function fromProtocolParamsRaw({
collateralPercent,
priceSteps,
priceMem,
+ maxTxSize,
+ maxValueSize,
+ utxoCostPerByte,
languageView,
}: ProtocolParamsRaw): ProtocolParams {
return {
@@ -147,6 +156,9 @@ function fromProtocolParamsRaw({
collateralPercent,
priceSteps,
priceMem,
+ maxTxSize,
+ maxValueSize,
+ utxoCostPerByte,
languageView,
};
}
diff --git a/libs/coin-modules/coin-cardano/src/signer.ts b/libs/coin-modules/coin-cardano/src/signer.ts
index 6174c3334700..0919cb4c4cfe 100644
--- a/libs/coin-modules/coin-cardano/src/signer.ts
+++ b/libs/coin-modules/coin-cardano/src/signer.ts
@@ -18,6 +18,11 @@ export type CardanoExtendedPublicKey = {
publicKeyHex: string;
chainCodeHex: string;
};
+// Coming from @cardano-foundation/ledgerjs-hw-app-cardano code (type TxOutputFormat)
+export enum CardanoTxOutputFormat {
+ ARRAY_LEGACY = 0,
+ MAP_BABBAGE = 1,
+}
export type GetAddressRequest = {
path: string;
stakingPathString: string;
@@ -31,6 +36,7 @@ export type SignerTxInput = {
path: string | null;
};
export type SignerTxOutput = {
+ format: CardanoTxOutputFormat;
amount: string;
destination:
| {
diff --git a/libs/coin-modules/coin-cardano/src/specs.ts b/libs/coin-modules/coin-cardano/src/specs.ts
index 293bc1441f51..f38d2000b45c 100644
--- a/libs/coin-modules/coin-cardano/src/specs.ts
+++ b/libs/coin-modules/coin-cardano/src/specs.ts
@@ -11,6 +11,7 @@ import { mergeTokens } from "./logic";
import { formatCurrencyUnit, parseCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
import { SubAccount } from "@ledgerhq/types-live";
import { acceptTransaction } from "./speculos-deviceActions";
+import { CARDANO_MAX_SUPPLY } from "./constants";
const maxAccounts = 5;
const currency = getCryptoCurrencyById("cardano");
@@ -143,16 +144,20 @@ const cardano: AppSpec = {
const cardanoResources = (account as CardanoAccount).cardanoResources as CardanoResources;
const utxoTokens = cardanoResources.utxos.map(u => u.tokens).flat();
const tokenBalance = mergeTokens(utxoTokens);
- const requiredAdaForTokens = tokenBalance.length
- ? TyphonUtils.calculateMinUtxoAmount(
- tokenBalance,
- new BigNumber(cardanoResources.protocolParams.lovelacePerUtxoWord),
- false,
+ const changeAddress = TyphonUtils.getAddressFromString(account.freshAddress);
+ const requiredAdaForChangeTokens = tokenBalance.length
+ ? TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: changeAddress,
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokenBalance,
+ },
+ new BigNumber(cardanoResources.protocolParams.utxoCostPerByte),
)
: new BigNumber(0);
botTest("remaining balance equals requiredAdaForTokens)", () =>
- expect(account.balance).toEqual(requiredAdaForTokens),
+ expect(account.balance).toEqual(requiredAdaForChangeTokens),
);
},
},
diff --git a/libs/coin-modules/coin-cardano/src/synchronisation.ts b/libs/coin-modules/coin-cardano/src/synchronisation.ts
index dcd320da556b..a8397aefb7ae 100644
--- a/libs/coin-modules/coin-cardano/src/synchronisation.ts
+++ b/libs/coin-modules/coin-cardano/src/synchronisation.ts
@@ -10,14 +10,13 @@ import { SignerContext } from "@ledgerhq/coin-framework/signer";
import { listTokensForCryptoCurrency } from "@ledgerhq/cryptoassets";
import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import { encodeAccountId } from "@ledgerhq/coin-framework/account/index";
-import { calculateMinUtxoAmount } from "@stricahq/typhonjs/dist/utils/utils";
import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
import { inferSubOperations } from "@ledgerhq/coin-framework/serialization/index";
import type { Operation, OperationType, TokenAccount } from "@ledgerhq/types-live";
import { getDelegationInfo } from "./api/getDelegationInfo";
import { APITransaction, HashType } from "./api/api-types";
import { getTransactions } from "./api/getTransactions";
-import { getNetworkInfo } from "./api/getNetworkInfo";
+import { fetchNetworkInfo } from "./api/getNetworkInfo";
import { buildSubAccounts } from "./buildSubAccounts";
import { getNetworkParameters } from "./networks";
import { CardanoSigner } from "./signer";
@@ -40,6 +39,7 @@ import {
isHexString,
mergeTokens,
} from "./logic";
+import { CARDANO_MAX_SUPPLY } from "./constants";
export const makeGetAccountShape =
(signerContext: SignerContext): GetAccountShape =>
@@ -148,16 +148,19 @@ export const makeGetAccountShape =
stakeCred: stakeCredential,
}).getBech32(),
}));
- const cardanoNetworkInfo = await getNetworkInfo(initialAccount, currency);
+ const cardanoNetworkInfo = await fetchNetworkInfo(currency);
const delegationInfo = await getDelegationInfo(currency, stakeCredential.key);
const totalBalance = delegationInfo?.rewards ? utxosSum.plus(delegationInfo.rewards) : utxosSum;
- const minAdaBalanceForTokens = tokenBalance.length
- ? calculateMinUtxoAmount(
- tokenBalance,
- new BigNumber(cardanoNetworkInfo.protocolParams.lovelacePerUtxoWord),
- false,
+ const minAdaForTokens = tokenBalance.length
+ ? TyphonUtils.calculateMinUtxoAmountBabbage(
+ {
+ address: TyphonUtils.getAddressFromString(freshAddresses[0].address),
+ amount: new BigNumber(CARDANO_MAX_SUPPLY),
+ tokens: tokenBalance,
+ },
+ new BigNumber(cardanoNetworkInfo.protocolParams.utxoCostPerByte),
)
: new BigNumber(0);
@@ -179,7 +182,7 @@ export const makeGetAccountShape =
id: accountId,
xpub,
balance: totalBalance,
- spendableBalance: utxosSum.minus(minAdaBalanceForTokens),
+ spendableBalance: BigNumber.max(0, utxosSum.minus(minAdaForTokens)),
operations: operations,
syncHash,
subAccounts,
@@ -289,10 +292,14 @@ function mapTxToAccountOperation(
fee: new BigNumber(tx.fees),
value: operationValue.absoluteValue(),
senders: tx.inputs.map(i =>
- isHexString(i.address) ? TyphonUtils.getAddressFromHex(i.address).getBech32() : i.address,
+ isHexString(i.address)
+ ? TyphonUtils.getAddressFromHex(Buffer.from(i.address, "hex")).getBech32()
+ : i.address,
),
recipients: tx.outputs.map(o =>
- isHexString(o.address) ? TyphonUtils.getAddressFromHex(o.address).getBech32() : o.address,
+ isHexString(o.address)
+ ? TyphonUtils.getAddressFromHex(Buffer.from(o.address, "hex")).getBech32()
+ : o.address,
),
subOperations,
blockHeight: tx.blockHeight,
diff --git a/libs/coin-modules/coin-cardano/src/synchronisation.unit.test.ts b/libs/coin-modules/coin-cardano/src/synchronisation.unit.test.ts
index dcfe2ced415d..e07851920faf 100644
--- a/libs/coin-modules/coin-cardano/src/synchronisation.unit.test.ts
+++ b/libs/coin-modules/coin-cardano/src/synchronisation.unit.test.ts
@@ -6,7 +6,7 @@ import { getDelegationInfo } from "./api/getDelegationInfo";
import { makeGetAccountShape } from "./synchronisation";
import { getTransactions } from "./api/getTransactions";
import { buildSubAccounts } from "./buildSubAccounts";
-import { getNetworkInfo } from "./api/getNetworkInfo";
+import { fetchNetworkInfo } from "./api/getNetworkInfo";
import { APINetworkInfo } from "./api/api-types";
import { CardanoSigner } from "./signer";
@@ -67,7 +67,7 @@ describe("makeGetAccountShape", () => {
const buildSubAccountsMock = jest.mocked(buildSubAccounts);
buildSubAccountsMock.mockReturnValue([]);
getTransactionsMock = jest.mocked(getTransactions);
- const getNetworkInfoMock = jest.mocked(getNetworkInfo);
+ const getNetworkInfoMock = jest.mocked(fetchNetworkInfo);
getNetworkInfoMock.mockReturnValue(
Promise.resolve({ protocolParams: { lovelacePerUtxoWord: "1" } } as APINetworkInfo),
);
@@ -124,7 +124,19 @@ describe("makeGetAccountShape", () => {
getTransactionsMock.mockReturnValue(
Promise.resolve({
transactions: [],
- externalCredentials: [{ path: "p", networkId: "id" }],
+ externalCredentials: [
+ {
+ isUsed: false,
+ key: "00000000000000000000000000000000000000000000000000000000",
+ path: {
+ purpose: 1852,
+ coin: 1815,
+ account: 0,
+ chain: 0,
+ index: 0,
+ },
+ },
+ ],
internalCredentials: [],
} as any),
);
diff --git a/libs/coin-modules/coin-cardano/src/types.ts b/libs/coin-modules/coin-cardano/src/types.ts
index 87651df4cd62..4d1e8bb437a5 100644
--- a/libs/coin-modules/coin-cardano/src/types.ts
+++ b/libs/coin-modules/coin-cardano/src/types.ts
@@ -107,6 +107,9 @@ export type ProtocolParams = {
collateralPercent: string;
priceSteps: string;
priceMem: string;
+ maxTxSize: string;
+ maxValueSize: string;
+ utxoCostPerByte: string;
languageView: TyphonTypes.LanguageView;
};
@@ -118,6 +121,9 @@ export type ProtocolParamsRaw = {
collateralPercent: string;
priceSteps: string;
priceMem: string;
+ maxTxSize: string;
+ maxValueSize: string;
+ utxoCostPerByte: string;
// TyphonTypes.LanguageView is already a raw type
languageView: TyphonTypes.LanguageView;
};
diff --git a/libs/coin-modules/coin-cardano/src/typhonSerializer.ts b/libs/coin-modules/coin-cardano/src/typhonSerializer.ts
index e6e58cc05f44..7ef6775e6efa 100644
--- a/libs/coin-modules/coin-cardano/src/typhonSerializer.ts
+++ b/libs/coin-modules/coin-cardano/src/typhonSerializer.ts
@@ -6,7 +6,13 @@ import {
import groupBy from "lodash/groupBy";
import { getBipPathString } from "./logic";
import { CertificateType } from "@stricahq/typhonjs/dist/types";
-import { SignerTxCertificate, SignerTxInput, SignerTxOutput, SignerTxWithdrawal } from "./signer";
+import {
+ CardanoTxOutputFormat,
+ SignerTxCertificate,
+ SignerTxInput,
+ SignerTxOutput,
+ SignerTxWithdrawal,
+} from "./signer";
/**
* Convert StricaTypes Transaction into a simpler types.
@@ -127,6 +133,7 @@ const prepareLedgerOutput =
);
return {
+ format: CardanoTxOutputFormat.MAP_BABBAGE,
amount: output.amount.toString(),
destination,
tokenBundle,
diff --git a/libs/coin-modules/coin-cosmos/.unimportedrc.json b/libs/coin-modules/coin-cosmos/.unimportedrc.json
new file mode 100644
index 000000000000..e84058c4b5e5
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/.unimportedrc.json
@@ -0,0 +1,40 @@
+{
+ "entry": [
+ "src/account.ts",
+ "src/bridge/index.ts",
+ "src/cli.ts",
+ "src/deviceTransactionConfig.ts",
+ "src/CosmosValidatorsManager.ts",
+ "src/errors.ts",
+ "src/formatters.ts",
+ "src/hw-getAddress.ts",
+ "src/initAccount.ts",
+ "src/mock.ts",
+ "src/preloadedData.ts",
+ "src/preloadedData.mock.ts",
+ "src/serialization.ts",
+ "src/specs.ts",
+ "src/transaction.ts"
+ ],
+ "ignorePatterns": [
+ "**/node_modules/**",
+ "**/*.fixture.ts",
+ "**/*.mock.ts",
+ "**/*.test.{js,jsx,ts,tsx}"
+ ],
+ "ignoreUnresolved": [],
+ "ignoreUnimported": [
+ "src/broadcast.ts",
+ "src/buildOptimisticOperation.ts",
+ "src/buildTransaction.ts",
+ "src/cli.ts",
+ "src/config.ts",
+ "src/createTransaction.ts",
+ "src/estimateMaxSpendable.ts",
+ "src/getTransactionStatus.ts",
+ "src/prepareTransaction.ts",
+ "src/signOperation.ts",
+ "src/synchronisation.ts"
+ ],
+ "ignoreUnused": ["rxjs"]
+}
diff --git a/libs/coin-modules/coin-cosmos/CHANGELOG.md b/libs/coin-modules/coin-cosmos/CHANGELOG.md
new file mode 100644
index 000000000000..1da00e9243c4
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/CHANGELOG.md
@@ -0,0 +1,37 @@
+# @ledgerhq/coin-cosmos
+
+## 0.1.1
+
+### Patch Changes
+
+- [#7735](https://github.com/LedgerHQ/ledger-live/pull/7735) [`c8ac662`](https://github.com/LedgerHQ/ledger-live/commit/c8ac662e6f88349187f802741e14c3d5fb67cddb) Thanks [@Wozacosta](https://github.com/Wozacosta)! - fix mock type in cosmos unit test and regen pnpm lock
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.1.1-next.0
+
+### Patch Changes
+
+- [#7735](https://github.com/LedgerHQ/ledger-live/pull/7735) [`c8ac662`](https://github.com/LedgerHQ/ledger-live/commit/c8ac662e6f88349187f802741e14c3d5fb67cddb) Thanks [@Wozacosta](https://github.com/Wozacosta)! - fix mock type in cosmos unit test and regen pnpm lock
+
+- [#7636](https://github.com/LedgerHQ/ledger-live/pull/7636) [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7) Thanks [@Wozacosta](https://github.com/Wozacosta)! - Move Cosmos and Cosmos-based coins to its own module
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
diff --git a/libs/coin-modules/coin-cosmos/jest.config.js b/libs/coin-modules/coin-cosmos/jest.config.js
new file mode 100644
index 000000000000..abe07c3fa244
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/jest.config.js
@@ -0,0 +1,9 @@
+/** @type {import('ts-jest/dist/types').JestConfigWithTsJest} */
+module.exports = {
+ collectCoverageFrom: ["src/**/*.ts"],
+ coverageDirectory: "coverage",
+ preset: "ts-jest",
+ testEnvironment: "node",
+ testPathIgnorePatterns: ["lib/", "lib-es/", ".integration.test.ts"],
+ modulePathIgnorePatterns: ["__tests__/fixtures"],
+};
diff --git a/libs/coin-modules/coin-cosmos/package.json b/libs/coin-modules/coin-cosmos/package.json
new file mode 100644
index 000000000000..1139327130dd
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/package.json
@@ -0,0 +1,93 @@
+{
+ "name": "@ledgerhq/coin-cosmos",
+ "version": "0.1.1",
+ "description": "Ledger Cosmos Coin integration",
+ "keywords": [
+ "Ledger",
+ "LedgerWallet",
+ "cosmos",
+ "CosmosHub",
+ "Hardware Wallet"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/LedgerHQ/ledger-live.git"
+ },
+ "bugs": {
+ "url": "https://github.com/LedgerHQ/ledger-live/issues"
+ },
+ "homepage": "https://github.com/LedgerHQ/ledger-live/tree/develop/libs/coin-modules/coin-cosmos",
+ "publishConfig": {
+ "access": "public"
+ },
+ "typesVersions": {
+ "*": {
+ "lib/*": [
+ "lib/*"
+ ],
+ "lib-es/*": [
+ "lib-es/*"
+ ],
+ "*": [
+ "lib/*"
+ ]
+ }
+ },
+ "exports": {
+ "./lib/*": "./lib/*.js",
+ "./lib-es/*": "./lib-es/*.js",
+ "./*": {
+ "require": "./lib/*.js",
+ "default": "./lib-es/*.js"
+ },
+ "./package.json": "./package.json"
+ },
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@cosmjs/amino": "^0.31.1",
+ "@cosmjs/crypto": "^0.31.0",
+ "@cosmjs/stargate": "^0.26.5",
+ "@keplr-wallet/cosmos": "^0.9.16",
+ "@keplr-wallet/proto-types": "^0.12.76",
+ "@ledgerhq/coin-framework": "workspace:^",
+ "@ledgerhq/cryptoassets": "workspace:^",
+ "@ledgerhq/devices": "workspace:^",
+ "@ledgerhq/errors": "workspace:^",
+ "@ledgerhq/live-config": "workspace:^",
+ "@ledgerhq/live-env": "workspace:^",
+ "@ledgerhq/live-network": "workspace:^",
+ "@ledgerhq/logs": "workspace:^",
+ "@ledgerhq/types-cryptoassets": "workspace:^",
+ "@ledgerhq/types-live": "workspace:^",
+ "axios": "0.26.1",
+ "bech32": "^1.1.3",
+ "bignumber.js": "^9.1.2",
+ "cosmjs-types": "0.2.1",
+ "expect": "^27.4.6",
+ "invariant": "^2.2.2",
+ "lodash": "^4.17.21",
+ "prando": "^6.0.1",
+ "rxjs": "^7.8.1",
+ "semver": "^7.1.3"
+ },
+ "devDependencies": {
+ "@types/invariant": "^2.2.2",
+ "@types/jest": "^29.5.10",
+ "@types/lodash": "^4.14.191",
+ "@types/semver": "^7.5.8",
+ "jest": "^29.7.0",
+ "ts-jest": "^29.1.1"
+ },
+ "scripts": {
+ "clean": "rimraf lib lib-es",
+ "build": "tsc && tsc -m ES6 --outDir lib-es",
+ "coverage": "jest --coverage --testPathIgnorePatterns='/bridge.integration.test.ts|node_modules|lib-es|lib/' --passWithNoTests && mv coverage/coverage-final.json coverage/coverage-algorand.json",
+ "prewatch": "pnpm build",
+ "watch": "tsc --watch",
+ "doc": "documentation readme src/** --section=API --pe ts --re ts --re d.ts",
+ "lint": "eslint ./src --no-error-on-unmatched-pattern --ext .ts,.tsx --cache",
+ "lint:fix": "pnpm lint --fix",
+ "test": "jest",
+ "unimported": "unimported"
+ }
+}
diff --git a/libs/ledger-live-common/src/families/cosmos/CosmosValidatorsManager.ts b/libs/coin-modules/coin-cosmos/src/CosmosValidatorsManager.ts
similarity index 95%
rename from libs/ledger-live-common/src/families/cosmos/CosmosValidatorsManager.ts
rename to libs/coin-modules/coin-cosmos/src/CosmosValidatorsManager.ts
index 2cc8e99a2ef7..63fe02927690 100644
--- a/libs/ledger-live-common/src/families/cosmos/CosmosValidatorsManager.ts
+++ b/libs/coin-modules/coin-cosmos/src/CosmosValidatorsManager.ts
@@ -1,8 +1,9 @@
+import { EnvName, EnvValue } from "@ledgerhq/live-env";
import { makeLRUCache } from "@ledgerhq/live-network/cache";
import network from "@ledgerhq/live-network/network";
import { log } from "@ledgerhq/logs";
import type { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
-import { EnvName, EnvValue } from "@ledgerhq/live-env";
+import { GetValidatorItem } from "./api/types";
import cryptoFactory from "./chain/chain";
import cosmosBase from "./chain/cosmosBase";
import type { CosmosValidatorItem } from "./types";
@@ -46,7 +47,7 @@ export class CosmosValidatorsManager {
url,
method: "GET",
});
- const validators = data.validators.map(validator => {
+ const validators = data.validators.map((validator: GetValidatorItem) => {
const commission = parseFloat(validator.commission.commission_rates.rate);
return {
validatorAddress: validator.operator_address,
diff --git a/libs/ledger-live-common/src/families/cosmos/api/Cosmos.ts b/libs/coin-modules/coin-cosmos/src/api/Cosmos.ts
similarity index 96%
rename from libs/ledger-live-common/src/families/cosmos/api/Cosmos.ts
rename to libs/coin-modules/coin-cosmos/src/api/Cosmos.ts
index 92fe16079b13..627f9fd9255b 100644
--- a/libs/ledger-live-common/src/families/cosmos/api/Cosmos.ts
+++ b/libs/coin-modules/coin-cosmos/src/api/Cosmos.ts
@@ -1,15 +1,14 @@
import { AxiosError } from "axios";
+import { patchOperationWithHash } from "@ledgerhq/coin-framework/operation";
+import { SequenceNumberError } from "@ledgerhq/errors";
import network from "@ledgerhq/live-network/network";
import { log } from "@ledgerhq/logs";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
-import { Operation } from "@ledgerhq/types-live";
+import { Operation, SignedOperation } from "@ledgerhq/types-live";
import BigNumber from "bignumber.js";
-import { SequenceNumberError } from "@ledgerhq/errors";
-import { patchOperationWithHash } from "../../../operation";
+import semver from "semver";
import cryptoFactory from "../chain/chain";
import cosmosBase from "../chain/cosmosBase";
-import * as CosmosSDKTypes from "./types";
-import semver from "semver";
import {
CosmosDelegation,
CosmosDelegationStatus,
@@ -17,6 +16,7 @@ import {
CosmosTx,
CosmosUnbonding,
} from "../types";
+import * as CosmosSDKTypes from "./types";
const USDC_DENOM = "ibc/8E27BA2D5493AF5636760E354E46004562C46AB7EC0CC4C1CA14E9E20E2545B5";
@@ -231,6 +231,7 @@ export class CosmosAPI {
BOND_STATUS_UNBONDED: "unbonded",
BOND_STATUS_UNBONDING: "unbonding",
BOND_STATUS_BONDED: "bonded",
+ BOND_STATUS_UNSPECIFIED: "unspecified",
};
for (const { delegation, balance } of filteredDelegationResponses) {
@@ -417,13 +418,16 @@ export class CosmosAPI {
total: number;
}> {
let cosmosSDKVersion = await this.cosmosSDKVersion;
- cosmosSDKVersion = semver.coerce(cosmosSDKVersion).version;
+ const coerceResult = semver.coerce(cosmosSDKVersion);
+ if (coerceResult != null) {
+ cosmosSDKVersion = coerceResult.version;
+ }
let queryparam = "events";
if (semver.gte(cosmosSDKVersion, "0.50.0")) {
queryparam = "query";
}
let serializedOptions = "";
- for (const key of Object.keys(options)) {
+ for (const key of Object.keys(options) as Array) {
serializedOptions += options[key] != null ? `&${key}=${options[key]}` : "";
}
const { data } = await network({
@@ -445,7 +449,11 @@ export class CosmosAPI {
* @deprecated body {..., mode } -> BROADCAST_MODE_BLOCK (Deprecated: post v0.47 use BROADCAST_MODE_SYNC instead)
* @notice returns {..., events } (Since: cosmos-sdk 0.42.11, 0.44.5, 0.45)
*/
- broadcast = async ({ signedOperation: { operation, signature } }): Promise => {
+ broadcast = async ({
+ signedOperation: { signature, operation },
+ }: {
+ signedOperation: SignedOperation;
+ }): Promise => {
const {
data: { tx_response: txResponse },
} = await network({
diff --git a/libs/ledger-live-common/src/families/cosmos/api/Cosmos.unit.test.ts b/libs/coin-modules/coin-cosmos/src/api/Cosmos.unit.test.ts
similarity index 89%
rename from libs/ledger-live-common/src/families/cosmos/api/Cosmos.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/api/Cosmos.unit.test.ts
index 049258dde981..4ca523d7f865 100644
--- a/libs/ledger-live-common/src/families/cosmos/api/Cosmos.unit.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/api/Cosmos.unit.test.ts
@@ -1,15 +1,22 @@
import network from "@ledgerhq/live-network/network";
-import { AxiosResponse } from "axios";
+import { Operation } from "@ledgerhq/types-live";
import BigNumber from "bignumber.js";
import cryptoFactory from "../chain/chain";
import { CosmosAPI } from "./Cosmos";
-import { LiveConfig } from "@ledgerhq/live-config/LiveConfig";
-import { liveConfig } from "../../../config/sharedConfig";
jest.mock("@ledgerhq/live-network/network");
const mockedNetwork = jest.mocked(network);
-
-LiveConfig.setConfig(liveConfig);
+const mockAxiosResponse = (data: any) => {
+ return mockedNetwork.mockResolvedValue({
+ data,
+ status: 200,
+ headers: {} as any,
+ statusText: "",
+ config: {
+ headers: {} as any,
+ },
+ });
+};
describe("CosmosApi", () => {
let cosmosApi: CosmosAPI;
@@ -24,20 +31,28 @@ describe("CosmosApi", () => {
describe("getAccount", () => {
it("should return base_account if available", async () => {
- mockedNetwork.mockResolvedValue({
- data: {
- account: {
- account_number: 1,
- sequence: 0,
- pub_key: { key: "k", "@type": "type" },
- base_account: {
- account_number: 2,
- sequence: 42,
- pub_key: { key: "k2", "@type": "type2" },
+ mockedNetwork.mockResolvedValue(
+ Promise.resolve({
+ data: {
+ account: {
+ account_number: 1,
+ sequence: 0,
+ pub_key: { key: "k", "@type": "type" },
+ base_account: {
+ account_number: 2,
+ sequence: 42,
+ pub_key: { key: "k2", "@type": "type2" },
+ },
},
},
- },
- } as AxiosResponse);
+ status: 200,
+ headers: {} as any,
+ statusText: "",
+ config: {
+ headers: {} as any,
+ },
+ }),
+ );
const account = await cosmosApi.getAccount("addr");
expect(account.accountNumber).toEqual(2);
@@ -47,16 +62,14 @@ describe("CosmosApi", () => {
});
it("should return the correct account based on type", async () => {
- mockedNetwork.mockResolvedValue({
- data: {
- account: {
- "@type": "/cosmos.auth.v1beta1.BaseAccount",
- account_number: 1,
- sequence: 0,
- pub_key: { key: "k", "@type": "type" },
- },
+ mockAxiosResponse({
+ account: {
+ "@type": "/cosmos.auth.v1beta1.BaseAccount",
+ account_number: 1,
+ sequence: 0,
+ pub_key: { key: "k", "@type": "type" },
},
- } as AxiosResponse);
+ });
const account = await cosmosApi.getAccount("addr");
expect(account).toEqual({
@@ -66,24 +79,22 @@ describe("CosmosApi", () => {
pubKeyType: "type",
});
- mockedNetwork.mockResolvedValue({
- data: {
- account: {
- "@type": "/ethermint.types.v1.EthAccount",
- account_number: 1,
- sequence: 0,
- pub_key: { key: "k", "@type": "type" },
+ mockAxiosResponse({
+ account: {
+ "@type": "/ethermint.types.v1.EthAccount",
+ account_number: 1,
+ sequence: 0,
+ pub_key: { key: "k", "@type": "type" },
- base_account: {
- address: "address",
- pub_key: { key: "k2", "@type": "type2" },
- account_number: 2,
- sequence: 3,
- },
- code_hash: "codeHash",
+ base_account: {
+ address: "address",
+ pub_key: { key: "k2", "@type": "type2" },
+ account_number: 2,
+ sequence: 3,
},
+ code_hash: "codeHash",
},
- } as AxiosResponse);
+ });
const ethermintAccount = await cosmosApi.getAccount("addr");
expect(ethermintAccount).toEqual({
@@ -147,9 +158,7 @@ describe("CosmosApi", () => {
total: "1",
},
};
- mockedNetwork.mockResolvedValue({
- data: getApiResponseSinceSdk041,
- } as AxiosResponse);
+ mockAxiosResponse(getApiResponseSinceSdk041);
const cosmosRedelegations = await cosmosApi.getRedelegations("cosmosDelegatorAddress");
expect(cosmosRedelegations[0].amount).toEqual(new BigNumber(100));
expect(cosmosRedelegations[0].completionDate).toEqual(new Date("2023-06-04T15:12:58.567Z"));
@@ -183,9 +192,8 @@ describe("CosmosApi", () => {
],
pagination: { next_key: null, total: "1" },
};
- mockedNetwork.mockResolvedValue({
- data: getApiResponseSinceSdk046,
- } as AxiosResponse);
+
+ mockAxiosResponse(getApiResponseSinceSdk046);
const cosmosRedelegations = await cosmosApi.getRedelegations("cosmosDelegatorAddress");
expect(cosmosRedelegations[0].amount).toEqual(new BigNumber(100));
@@ -197,9 +205,7 @@ describe("CosmosApi", () => {
});
it("should return no redelegations if there are none", async () => {
- mockedNetwork.mockResolvedValue({
- data: { redelegation_responses: [], pagination: { next_key: null, total: "0" } },
- } as AxiosResponse);
+ mockAxiosResponse({ redelegation_responses: [], pagination: { next_key: null, total: "0" } });
const cosmosRedelegations = await cosmosApi.getRedelegations("cosmosDelegatorAddress");
expect(cosmosRedelegations.length).toEqual(0);
@@ -208,21 +214,20 @@ describe("CosmosApi", () => {
describe("simulate", () => {
it("should return gas used when the network call returns gas used", async () => {
- mockedNetwork.mockResolvedValue({
- data: {
- gas_info: {
- gas_used: 42000,
- },
+ mockAxiosResponse({
+ gas_info: {
+ gas_used: 42000,
},
- } as AxiosResponse);
+ });
const gas = await cosmosApi.simulate([]);
expect(gas).toEqual(new BigNumber(42000));
});
it("should throw an error when the network call does not return gas used", async () => {
- mockedNetwork.mockResolvedValue({
- data: { gas_info: {} },
- } as AxiosResponse);
+ mockAxiosResponse({
+ gas_info: {},
+ });
+
await expect(cosmosApi.simulate([])).rejects.toThrowError();
});
@@ -593,11 +598,11 @@ describe("CosmosApi", () => {
describe("broadcastTransaction", () => {
it("should throw a SequenceNumberError exception in case of sequence number error", async () => {
- mockedNetwork.mockResolvedValue({
- data: { tx_response: { code: 32 } },
- } as AxiosResponse);
+ mockAxiosResponse({ tx_response: { code: 32 } });
await expect(
- cosmosApi.broadcast({ signedOperation: { operation: null, signature: "signedOperation" } }),
+ cosmosApi.broadcast({
+ signedOperation: { operation: {} as Operation, signature: "signedOperation" },
+ }),
).rejects.toThrow("SequenceNumberError");
});
});
diff --git a/libs/ledger-live-common/src/families/cosmos/api/types.ts b/libs/coin-modules/coin-cosmos/src/api/types.ts
similarity index 97%
rename from libs/ledger-live-common/src/families/cosmos/api/types.ts
rename to libs/coin-modules/coin-cosmos/src/api/types.ts
index 3a9dca88c014..8fe19769c8ea 100644
--- a/libs/ledger-live-common/src/families/cosmos/api/types.ts
+++ b/libs/coin-modules/coin-cosmos/src/api/types.ts
@@ -339,3 +339,10 @@ export type PostSimulate = {
msg_responses: { "@type": string; value: string }[];
};
};
+
+export type GetValidatorItem = {
+ operator_address: string;
+ description: { moniker: string };
+ tokens: string;
+ commission: { commission_rates: { rate: string } };
+};
diff --git a/libs/ledger-live-common/src/families/cosmos/bridge/js.test.ts b/libs/coin-modules/coin-cosmos/src/bridge/index.test.ts
similarity index 79%
rename from libs/ledger-live-common/src/families/cosmos/bridge/js.test.ts
rename to libs/coin-modules/coin-cosmos/src/bridge/index.test.ts
index b51d3b0091a2..82cb84aea56d 100644
--- a/libs/ledger-live-common/src/families/cosmos/bridge/js.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/bridge/index.test.ts
@@ -1,25 +1,27 @@
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
-import currencyBridge from "./js";
-jest.mock("../chain/chain");
+import { CurrencyBridge } from "@ledgerhq/types-live";
import cryptoFactory from "../chain/chain";
-jest.mock("../CosmosValidatorsManager");
import cosmosBase from "../chain/cosmosBase";
+
+jest.mock("../CosmosValidatorsManager");
const mockedCryptoFactory = jest.mocked(cryptoFactory);
-describe("currencyBridge", () => {
+describe.skip("currencyBridge", () => {
+ let currencyBridge: CurrencyBridge;
describe("hydrate", () => {
+ beforeEach(() => {});
afterEach(() => {
jest.resetAllMocks();
});
const currencyMock = {} as CryptoCurrency;
it("shouldn't update configuration if data is undefined", () => {
- currencyBridge.currencyBridge.hydrate(undefined, currencyMock);
+ currencyBridge.hydrate(undefined, currencyMock);
expect(mockedCryptoFactory).not.toHaveBeenCalled();
});
it("shouldn't update configuration if data is not an object", () => {
- currencyBridge.currencyBridge.hydrate("definitely not an object", currencyMock);
+ currencyBridge.hydrate("definitely not an object", currencyMock);
expect(mockedCryptoFactory).not.toHaveBeenCalled();
});
@@ -35,7 +37,7 @@ describe("currencyBridge", () => {
ledgerValidator: "ledgerValidatorAddress",
};
mockedCryptoFactory.mockReturnValue(config as cosmosBase);
- currencyBridge.currencyBridge.hydrate(
+ currencyBridge.hydrate(
{
config: newConfig,
},
diff --git a/libs/coin-modules/coin-cosmos/src/bridge/index.ts b/libs/coin-modules/coin-cosmos/src/bridge/index.ts
new file mode 100644
index 000000000000..e9e729e1ef2f
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/bridge/index.ts
@@ -0,0 +1,87 @@
+import getAddressWrapper from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
+import {
+ makeAccountBridgeReceive,
+ makeScanAccounts,
+ makeSync,
+} from "@ledgerhq/coin-framework/bridge/jsHelpers";
+import { SignerContext } from "@ledgerhq/coin-framework/signer";
+import type { AccountBridge, CurrencyBridge } from "@ledgerhq/types-live";
+
+import { CoinConfig } from "@ledgerhq/coin-framework/lib/config";
+import { CosmosAPI } from "../api/Cosmos";
+import cosmosCoinConfig, { CosmosCoinConfig } from "../config";
+import { createTransaction } from "../createTransaction";
+import { estimateMaxSpendable } from "../estimateMaxSpendable";
+import getTransactionStatus from "../getTransactionStatus";
+import resolver from "../hw-getAddress";
+import { prepareTransaction } from "../prepareTransaction";
+import {
+ assignFromAccountRaw,
+ assignToAccountRaw,
+ fromOperationExtraRaw,
+ toOperationExtraRaw,
+} from "../serialization";
+import { buildSignOperation } from "../signOperation";
+import { getAccountShape } from "../synchronisation";
+import type { CosmosAccount, Transaction, TransactionStatus } from "../types";
+import { CosmosSigner } from "../types/signer";
+import { updateTransaction } from "../updateTransaction";
+import { getPreloadStrategy, hydrate, preload } from "./preload";
+
+const sync = makeSync({ getAccountShape });
+
+function buildCurrencyBridge(signerContext: SignerContext): CurrencyBridge {
+ const getAddress = resolver(signerContext);
+
+ const scanAccounts = makeScanAccounts({
+ getAccountShape,
+ getAddressFn: getAddressWrapper(getAddress),
+ });
+
+ return {
+ getPreloadStrategy,
+ preload,
+ hydrate,
+ scanAccounts,
+ };
+}
+
+function buildAccountBridge(
+ signerContext: SignerContext,
+): AccountBridge {
+ const getAddress = resolver(signerContext);
+
+ const receive = makeAccountBridgeReceive(getAddressWrapper(getAddress));
+ const signOperation = buildSignOperation(signerContext);
+
+ return {
+ createTransaction,
+ updateTransaction,
+ prepareTransaction,
+ estimateMaxSpendable,
+ getTransactionStatus,
+ sync,
+ receive,
+ signOperation,
+ assignFromAccountRaw,
+ assignToAccountRaw,
+ broadcast: async ({ account, signedOperation }) => {
+ return new CosmosAPI(account.currency.id).broadcast({
+ signedOperation,
+ });
+ },
+ fromOperationExtraRaw,
+ toOperationExtraRaw,
+ };
+}
+
+export function createBridges(
+ signerContext: SignerContext,
+ coinConfig: CoinConfig,
+) {
+ cosmosCoinConfig.setCoinConfig(coinConfig);
+ return {
+ currencyBridge: buildCurrencyBridge(signerContext),
+ accountBridge: buildAccountBridge(signerContext),
+ };
+}
diff --git a/libs/coin-modules/coin-cosmos/src/bridge/preload.ts b/libs/coin-modules/coin-cosmos/src/bridge/preload.ts
new file mode 100644
index 000000000000..1d5b71ebdad6
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/bridge/preload.ts
@@ -0,0 +1,44 @@
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets";
+import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
+
+import { CosmosValidatorsManager } from "../CosmosValidatorsManager";
+import cryptoFactory from "../chain/chain";
+import cosmosCoinConfig from "../config";
+import { asSafeCosmosPreloadData, setCosmosPreloadData } from "../preloadedData";
+import type { CosmosCurrencyConfig, CosmosValidatorItem } from "../types";
+
+export const getPreloadStrategy = () => ({
+ preloadMaxAge: 30 * 1000,
+});
+
+export const preload = async (currency: CryptoCurrency) => {
+ const config = cosmosCoinConfig.getCoinConfig(currency);
+ const cosmosValidatorsManager = new CosmosValidatorsManager(getCryptoCurrencyById(currency.id), {
+ endPoint: (config as unknown as CosmosCurrencyConfig).lcd,
+ });
+ const validators = await cosmosValidatorsManager.getValidators();
+ setCosmosPreloadData(currency.id, {
+ validators,
+ });
+
+ return Promise.resolve({
+ validators,
+ config,
+ });
+};
+
+export const hydrate = (
+ data: { validators?: CosmosValidatorItem[]; config: CosmosCurrencyConfig },
+ currency: CryptoCurrency,
+) => {
+ if (!data || typeof data !== "object") return;
+ const relatedImpl = cryptoFactory(currency.id);
+ relatedImpl.lcd = data.config.lcd;
+ relatedImpl.minGasPrice = data.config.minGasPrice;
+ relatedImpl.ledgerValidator = data.config?.ledgerValidator;
+ const { validators } = data;
+ if (!validators || typeof validators !== "object" || !Array.isArray(validators)) return;
+ const cosmosValidatorsManager = new CosmosValidatorsManager(getCryptoCurrencyById(currency.id));
+ cosmosValidatorsManager.hydrateValidators(validators);
+ setCosmosPreloadData(currency.id, asSafeCosmosPreloadData(data));
+};
diff --git a/libs/ledger-live-common/src/families/cosmos/buildTransaction.ts b/libs/coin-modules/coin-cosmos/src/buildTransaction.ts
similarity index 98%
rename from libs/ledger-live-common/src/families/cosmos/buildTransaction.ts
rename to libs/coin-modules/coin-cosmos/src/buildTransaction.ts
index d02832243dea..ae2d4f63a427 100644
--- a/libs/ledger-live-common/src/families/cosmos/buildTransaction.ts
+++ b/libs/coin-modules/coin-cosmos/src/buildTransaction.ts
@@ -1,23 +1,22 @@
import {
+ AminoMsgBeginRedelegate,
+ AminoMsgDelegate,
+ AminoMsgSend,
+ AminoMsgUndelegate,
+ AminoMsgWithdrawDelegatorReward,
+} from "@cosmjs/stargate";
+import {
+ MsgBeginRedelegate,
MsgDelegate,
MsgUndelegate,
- MsgBeginRedelegate,
} from "cosmjs-types/cosmos/staking/v1beta1/tx";
import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx";
import { SignMode } from "cosmjs-types/cosmos/tx/signing/v1beta1/signing";
-import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
-import type { Account } from "@ledgerhq/types-live";
-import {
- AminoMsgSend,
- AminoMsgDelegate,
- AminoMsgUndelegate,
- AminoMsgBeginRedelegate,
- AminoMsgWithdrawDelegatorReward,
-} from "@cosmjs/stargate";
+import { TxBody, TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
import { cosmos } from "@keplr-wallet/cosmos";
import { PubKey } from "@keplr-wallet/proto-types/cosmos/crypto/secp256k1/keys";
import { AuthInfo, Fee } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx";
-import { TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx";
+import type { Account } from "@ledgerhq/types-live";
import { Transaction } from "./types";
type ProtoMsg = {
diff --git a/libs/ledger-live-common/src/families/cosmos/buildTransaction.unit.test.ts b/libs/coin-modules/coin-cosmos/src/buildTransaction.unit.test.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/buildTransaction.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/buildTransaction.unit.test.ts
index 11f41eaa4016..03e3ec4e11b9 100644
--- a/libs/ledger-live-common/src/families/cosmos/buildTransaction.unit.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/buildTransaction.unit.test.ts
@@ -1,17 +1,17 @@
import BigNumber from "bignumber.js";
-import { buildTransaction, txToMessages } from "./buildTransaction";
-import { CosmosAccount, CosmosDelegationInfo, Transaction } from "./types";
import {
+ MsgBeginRedelegate,
MsgDelegate,
MsgUndelegate,
- MsgBeginRedelegate,
} from "cosmjs-types/cosmos/staking/v1beta1/tx";
-
-import { cosmos } from "@keplr-wallet/cosmos";
import { MsgWithdrawDelegatorReward } from "cosmjs-types/cosmos/distribution/v1beta1/tx";
import { TxBody, TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx";
+import { cosmos } from "@keplr-wallet/cosmos";
import { Fee } from "@keplr-wallet/proto-types/cosmos/tx/v1beta1/tx";
+import { buildTransaction, txToMessages } from "./buildTransaction";
+import { CosmosAccount, CosmosDelegationInfo, Transaction } from "./types";
+
const veryBigNumber = new BigNumber(3333300000000000000000);
describe("txToMessages", () => {
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Axelar.ts b/libs/coin-modules/coin-cosmos/src/chain/Axelar.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Axelar.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Axelar.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/BinanceBeaconChain.ts b/libs/coin-modules/coin-cosmos/src/chain/BinanceBeaconChain.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/BinanceBeaconChain.ts
rename to libs/coin-modules/coin-cosmos/src/chain/BinanceBeaconChain.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Coreum.ts b/libs/coin-modules/coin-cosmos/src/chain/Coreum.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Coreum.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Coreum.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Cosmos.ts b/libs/coin-modules/coin-cosmos/src/chain/Cosmos.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Cosmos.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Cosmos.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Desmos.ts b/libs/coin-modules/coin-cosmos/src/chain/Desmos.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Desmos.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Desmos.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Dydx.ts b/libs/coin-modules/coin-cosmos/src/chain/Dydx.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Dydx.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Dydx.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Injective.ts b/libs/coin-modules/coin-cosmos/src/chain/Injective.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Injective.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Injective.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Nyx.ts b/libs/coin-modules/coin-cosmos/src/chain/Nyx.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Nyx.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Nyx.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Onomy.ts b/libs/coin-modules/coin-cosmos/src/chain/Onomy.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Onomy.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Onomy.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Osmosis.ts b/libs/coin-modules/coin-cosmos/src/chain/Osmosis.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Osmosis.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Osmosis.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Persistence.ts b/libs/coin-modules/coin-cosmos/src/chain/Persistence.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Persistence.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Persistence.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Quicksilver.ts b/libs/coin-modules/coin-cosmos/src/chain/Quicksilver.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Quicksilver.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Quicksilver.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/SecretNetwork.ts b/libs/coin-modules/coin-cosmos/src/chain/SecretNetwork.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/SecretNetwork.ts
rename to libs/coin-modules/coin-cosmos/src/chain/SecretNetwork.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/SeiNetwork.ts b/libs/coin-modules/coin-cosmos/src/chain/SeiNetwork.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/SeiNetwork.ts
rename to libs/coin-modules/coin-cosmos/src/chain/SeiNetwork.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Stargaze.ts b/libs/coin-modules/coin-cosmos/src/chain/Stargaze.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Stargaze.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Stargaze.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Stride.ts b/libs/coin-modules/coin-cosmos/src/chain/Stride.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Stride.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Stride.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/Umee.ts b/libs/coin-modules/coin-cosmos/src/chain/Umee.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/Umee.ts
rename to libs/coin-modules/coin-cosmos/src/chain/Umee.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/chain.ts b/libs/coin-modules/coin-cosmos/src/chain/chain.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/chain/chain.ts
rename to libs/coin-modules/coin-cosmos/src/chain/chain.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/chain.unit.test.ts b/libs/coin-modules/coin-cosmos/src/chain/chain.unit.test.ts
similarity index 79%
rename from libs/ledger-live-common/src/families/cosmos/chain/chain.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/chain/chain.unit.test.ts
index 527f368d7016..28850ed36ea7 100644
--- a/libs/ledger-live-common/src/families/cosmos/chain/chain.unit.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/chain/chain.unit.test.ts
@@ -1,12 +1,6 @@
import cryptoFactory from "./chain";
-import { LiveConfig } from "@ledgerhq/live-config/LiveConfig";
-import { liveConfig } from "../../../config/sharedConfig";
describe("cryptoFactory test", () => {
- beforeAll(() => {
- LiveConfig.setConfig(liveConfig);
- });
-
it("should not return null with currencies in cosmos family", () => {
const currencies = [
"cosmos",
diff --git a/libs/ledger-live-common/src/families/cosmos/chain/cosmosBase.ts b/libs/coin-modules/coin-cosmos/src/chain/cosmosBase.ts
similarity index 89%
rename from libs/ledger-live-common/src/families/cosmos/chain/cosmosBase.ts
rename to libs/coin-modules/coin-cosmos/src/chain/cosmosBase.ts
index d538e860c87a..37a201cd7a7f 100644
--- a/libs/ledger-live-common/src/families/cosmos/chain/cosmosBase.ts
+++ b/libs/coin-modules/coin-cosmos/src/chain/cosmosBase.ts
@@ -2,7 +2,7 @@ abstract class cosmosBase {
abstract lcd: string;
abstract stakingDocUrl: string;
abstract unbondingPeriod: number;
- abstract ledgerValidator?: string;
+ abstract ledgerValidator: string | undefined;
abstract validatorPrefix: string;
abstract prefix: string;
defaultPubKeyType = "/cosmos.crypto.secp256k1.PubKey";
diff --git a/libs/ledger-live-common/src/families/cosmos/cli-transaction.ts b/libs/coin-modules/coin-cosmos/src/cli.ts
similarity index 85%
rename from libs/ledger-live-common/src/families/cosmos/cli-transaction.ts
rename to libs/coin-modules/coin-cosmos/src/cli.ts
index 0980f8025e9a..d1ed789b58d7 100644
--- a/libs/ledger-live-common/src/families/cosmos/cli-transaction.ts
+++ b/libs/coin-modules/coin-cosmos/src/cli.ts
@@ -1,14 +1,14 @@
-import { from, Observable } from "rxjs";
-import { map } from "rxjs/operators";
+import { BigNumber } from "bignumber.js";
import invariant from "invariant";
import flatMap from "lodash/flatMap";
import zipWith from "lodash/zipWith";
-import { BigNumber } from "bignumber.js";
-import { Transaction as CosmosTransaction } from "./types";
-import type { CosmosDelegationInfo } from "./types";
+import { from, Observable } from "rxjs";
+import { map } from "rxjs/operators";
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/index";
import { AccountLike } from "@ledgerhq/types-live";
-import { getCryptoCurrencyById } from "../../currencies";
import { CosmosValidatorsManager } from "./CosmosValidatorsManager";
+import type { CosmosDelegationInfo } from "./types";
+import { Transaction as CosmosTransaction } from "./types";
const options = [
{
@@ -61,9 +61,11 @@ function inferTransactions(
return flatMap(transactions, ({ transaction, account }) => {
invariant(transaction.family === "cosmos", "cosmos family");
const validatorsAddresses: string[] = opts["cosmosValidator"] || [];
- const validatorsAmounts: BigNumber[] = (opts["cosmosAmountValidator"] || []).map(value => {
- return inferAmount(account, value);
- });
+ const validatorsAmounts: BigNumber[] = (opts["cosmosAmountValidator"] || []).map(
+ (value: any) => {
+ return inferAmount(account, value);
+ },
+ );
const validators: CosmosDelegationInfo[] = zipWith(
validatorsAddresses,
validatorsAmounts,
@@ -86,11 +88,11 @@ function inferTransactions(
}
const cosmosValidatorsFormatters = {
- json: list => JSON.stringify(list),
- default: list =>
+ json: (list: any) => JSON.stringify(list),
+ default: (list: any) =>
list
.map(
- v =>
+ (v: any) =>
`${v.validatorAddress} "${v.name}" ${v.votingPower} ${v.commission} ${v.estimatedYearlyRewardsRate}`,
)
.join("\n"),
@@ -112,15 +114,19 @@ const cosmosValidators = {
from(cosmosValidatorsManager.getValidators()).pipe(
map(validators => {
const f =
- (format && cosmosValidatorsFormatters[format]) || cosmosValidatorsFormatters.default;
+ (format && (cosmosValidatorsFormatters as any)[format]) ||
+ cosmosValidatorsFormatters.default;
return f(validators);
}),
),
};
-export default {
- options,
- inferTransactions,
- commands: {
- cosmosValidators,
- },
-};
+
+export default function makeCliTools() {
+ return {
+ options,
+ inferTransactions,
+ commands: {
+ cosmosValidators,
+ },
+ };
+}
diff --git a/libs/coin-modules/coin-cosmos/src/config.ts b/libs/coin-modules/coin-cosmos/src/config.ts
new file mode 100644
index 000000000000..d4ff7ec7b7b2
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/config.ts
@@ -0,0 +1,167 @@
+import { ConfigInfo } from "@ledgerhq/live-config/LiveConfig";
+
+type CosmosConfig = Record;
+
+export const cosmosConfig: CosmosConfig = {
+ config_currency_axelar: {
+ type: "object",
+ default: {
+ lcd: "https://axelar-api.polkachu.com",
+ minGasPrice: 0.07,
+ ledgerValidator: "axelarvaloper1fgklp9hemczlwtqp9jqzq3xahh38hznx7vd805",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_cosmos: {
+ type: "object",
+ default: {
+ lcd: "https://cosmoshub4.coin.ledger.com",
+ minGasPrice: 0.025,
+ ledgerValidator: "cosmosvaloper10wljxpl03053h9690apmyeakly3ylhejrucvtm",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_desmos: {
+ type: "object",
+ default: {
+ lcd: "https://desmos-api.ibs.team",
+ minGasPrice: 0.0025,
+ },
+ },
+ config_currency_dydx: {
+ type: "object",
+ default: {
+ lcd: "https://dydx-dao-api.polkachu.com",
+ minGasPrice: 12500000000,
+ ledgerValidator: "dydxvaloper1gffkd68xcnfpzcsplf0fsuetxkysunud6a900w",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_nyx: {
+ type: "object",
+ default: {
+ lcd: "https://api.nyx.nodes.guru",
+ minGasPrice: 0,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_onomy: {
+ type: "object",
+ default: {
+ lcd: "https://rest-mainnet.onomy.io",
+ minGasPrice: 0.003,
+ ledgerValidator: "onomyvaloper1fgklp9hemczlwtqp9jqzq3xahh38hznxu9mtmf",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_osmo: {
+ type: "object",
+ default: {
+ lcd: "https://osmosis-api.polkachu.com",
+ minGasPrice: 0.025,
+ ledgerValidator: "osmovaloper17cp6fxccqxrpj4zc00w2c7u6y0umc2jajsyc5t",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_persistence: {
+ type: "object",
+ default: {
+ lcd: "https://rest.core.persistence.one",
+ minGasPrice: 0.025,
+ ledgerValidator: "persistencevaloper1fgklp9hemczlwtqp9jqzq3xahh38hznxatty38",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_quicksilver: {
+ type: "object",
+ default: {
+ lcd: "https://lcd.quicksilver.zone",
+ minGasPrice: 0.0025,
+ ledgerValidator: "quickvaloper1fgklp9hemczlwtqp9jqzq3xahh38hznx02n4pp",
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_secret_network: {
+ type: "object",
+ default: {
+ lcd: "https://lcd.secret.express",
+ minGasPrice: 0.25,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_sei_network: {
+ type: "object",
+ default: {
+ lcd: "https://sei-api.polkachu.com",
+ minGasPrice: 0.1,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_stargaze: {
+ type: "object",
+ default: {
+ lcd: "https://stargaze-api.polkachu.com",
+ minGasPrice: 1,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_umee: {
+ type: "object",
+ default: {
+ lcd: "https://umee-api.polkachu.com",
+ minGasPrice: 0.1,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_coreum: {
+ type: "object",
+ default: {
+ lcd: "https://full-node.mainnet-1.coreum.dev:1317",
+ minGasPrice: 0.1,
+ status: {
+ type: "active",
+ },
+ },
+ },
+ config_currency_injective: {
+ type: "object",
+ default: {
+ lcd: "https://injective-api.polkachu.com",
+ minGasPrice: 900000000,
+ ledgerValidator: "injvaloper1ntn4j2lsu3k60g8xj9pqshqvdj2q5tygyvczpy",
+ status: {
+ type: "active",
+ },
+ },
+ },
+};
+
+import buildCoinConfig, { type CurrencyConfig } from "@ledgerhq/coin-framework/config";
+
+export type CosmosCoinConfig = CurrencyConfig & CosmosConfig;
+const coinConfig = buildCoinConfig();
+export default coinConfig;
diff --git a/libs/ledger-live-common/src/families/cosmos/createTransaction.ts b/libs/coin-modules/coin-cosmos/src/createTransaction.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/createTransaction.ts
rename to libs/coin-modules/coin-cosmos/src/createTransaction.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/deviceTransactionConfig.ts b/libs/coin-modules/coin-cosmos/src/deviceTransactionConfig.ts
similarity index 92%
rename from libs/ledger-live-common/src/families/cosmos/deviceTransactionConfig.ts
rename to libs/coin-modules/coin-cosmos/src/deviceTransactionConfig.ts
index b33f6b7e5b0e..0bc470f1c91d 100644
--- a/libs/ledger-live-common/src/families/cosmos/deviceTransactionConfig.ts
+++ b/libs/coin-modules/coin-cosmos/src/deviceTransactionConfig.ts
@@ -1,9 +1,11 @@
+import type { CommonDeviceTransactionField } from "@ledgerhq/coin-framework/transaction/common";
import type { AccountLike, Account } from "@ledgerhq/types-live";
import type { Transaction, TransactionStatus } from "./types";
-import type { DeviceTransactionField } from "../../transaction";
-import { getMainAccount } from "../../account";
-import { getAccountCurrency } from "../../account";
-import { formatCurrencyUnit } from "../../currencies";
+
+export type DeviceTransactionField = CommonDeviceTransactionField | ExtraDeviceTransactionField;
+
+import { getMainAccount, getAccountCurrency } from "@ledgerhq/coin-framework/account";
+import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
export type ExtraDeviceTransactionField =
| {
type: "cosmos.delegateValidators";
diff --git a/libs/coin-modules/coin-cosmos/src/errors.ts b/libs/coin-modules/coin-cosmos/src/errors.ts
new file mode 100644
index 000000000000..1b973ae31188
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/errors.ts
@@ -0,0 +1,9 @@
+import { createCustomErrorClass } from "@ledgerhq/errors";
+
+export const CosmosRedelegationInProgress = createCustomErrorClass("CosmosRedelegationInProgress");
+export const CosmosDelegateAllFundsWarning = createCustomErrorClass(
+ "CosmosDelegateAllFundsWarning",
+);
+export const CosmosTooManyValidators = createCustomErrorClass("CosmosTooManyValidators");
+export const NotEnoughDelegationBalance = createCustomErrorClass("NotEnoughDelegationBalance");
+export const ClaimRewardsFeesWarning = createCustomErrorClass("ClaimRewardsFeesWarning");
diff --git a/libs/ledger-live-common/src/families/cosmos/estimateMaxSpendable.ts b/libs/coin-modules/coin-cosmos/src/estimateMaxSpendable.ts
similarity index 92%
rename from libs/ledger-live-common/src/families/cosmos/estimateMaxSpendable.ts
rename to libs/coin-modules/coin-cosmos/src/estimateMaxSpendable.ts
index 2a71a9c92ec1..2a72eb746503 100644
--- a/libs/ledger-live-common/src/families/cosmos/estimateMaxSpendable.ts
+++ b/libs/coin-modules/coin-cosmos/src/estimateMaxSpendable.ts
@@ -1,10 +1,10 @@
-import type { AccountBridge } from "@ledgerhq/types-live";
+import { getMainAccount } from "@ledgerhq/coin-framework/account/index";
import { getAbandonSeedAddress } from "@ledgerhq/cryptoassets";
-import type { CosmosAccount, Transaction } from "./types";
+import type { AccountBridge } from "@ledgerhq/types-live";
+import { createTransaction } from "./createTransaction";
import getTransactionStatus from "./getTransactionStatus";
import { prepareTransaction } from "./prepareTransaction";
-import { createTransaction } from "./createTransaction";
-import { getMainAccount } from "../../account";
+import type { CosmosAccount, Transaction } from "./types";
export const estimateMaxSpendable: AccountBridge<
Transaction,
diff --git a/libs/ledger-live-common/src/families/cosmos/formatters.ts b/libs/coin-modules/coin-cosmos/src/formatters.ts
similarity index 92%
rename from libs/ledger-live-common/src/families/cosmos/formatters.ts
rename to libs/coin-modules/coin-cosmos/src/formatters.ts
index 27ebb2c3176d..7b81067642d5 100644
--- a/libs/ledger-live-common/src/families/cosmos/formatters.ts
+++ b/libs/coin-modules/coin-cosmos/src/formatters.ts
@@ -1,11 +1,11 @@
-import invariant from "invariant";
import { BigNumber } from "bignumber.js";
-import { getCurrentCosmosPreloadData } from "./preloadedData";
-import { getAccountCurrency } from "../../account";
-import { formatCurrencyUnit } from "../../currencies";
-import { CosmosOperation, CosmosAccount } from "./types";
-import { mapDelegations, mapUnbondings, mapRedelegations } from "./logic";
+import invariant from "invariant";
+import { getAccountCurrency } from "@ledgerhq/coin-framework/account";
+import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
import type { Unit } from "@ledgerhq/types-cryptoassets";
+import { mapDelegations, mapRedelegations, mapUnbondings } from "./logic";
+import { getCurrentCosmosPreloadData } from "./preloadedData";
+import { CosmosAccount, CosmosOperation } from "./types";
function formatOperationSpecifics(op: CosmosOperation, unit: Unit | null | undefined): string {
const { validators } = op.extra;
diff --git a/libs/ledger-live-common/src/families/cosmos/getTransactionStatus.ts b/libs/coin-modules/coin-cosmos/src/getTransactionStatus.ts
similarity index 99%
rename from libs/ledger-live-common/src/families/cosmos/getTransactionStatus.ts
rename to libs/coin-modules/coin-cosmos/src/getTransactionStatus.ts
index 4c2b406b0fc4..582c9995dbdd 100644
--- a/libs/ledger-live-common/src/families/cosmos/getTransactionStatus.ts
+++ b/libs/coin-modules/coin-cosmos/src/getTransactionStatus.ts
@@ -1,3 +1,7 @@
+import * as bech32 from "bech32";
+import { BigNumber } from "bignumber.js";
+import invariant from "invariant";
+import { findCryptoCurrencyById } from "@ledgerhq/cryptoassets";
import {
AmountRequired,
FeeNotLoaded,
@@ -7,32 +11,28 @@ import {
RecipientRequired,
RecommendUndelegation,
} from "@ledgerhq/errors";
+import { AccountBridge } from "@ledgerhq/types-live";
+import cryptoFactory from "./chain/chain";
import {
ClaimRewardsFeesWarning,
CosmosDelegateAllFundsWarning,
CosmosRedelegationInProgress,
CosmosTooManyValidators,
NotEnoughDelegationBalance,
-} from "../../errors";
-import {
- CosmosLikeTransaction,
- StatusErrorMap,
- CosmosAccount,
- TransactionStatus,
- Transaction,
-} from "./types";
-import { BigNumber } from "bignumber.js";
+} from "./errors";
import {
COSMOS_MAX_DELEGATIONS,
COSMOS_MAX_REDELEGATIONS,
COSMOS_MAX_UNBONDINGS,
getMaxEstimatedBalance,
} from "./logic";
-import invariant from "invariant";
-import * as bech32 from "bech32";
-import { findCryptoCurrencyById } from "@ledgerhq/cryptoassets";
-import cryptoFactory from "./chain/chain";
-import { AccountBridge } from "@ledgerhq/types-live";
+import {
+ CosmosAccount,
+ CosmosLikeTransaction,
+ StatusErrorMap,
+ Transaction,
+ TransactionStatus,
+} from "./types";
export class CosmosTransactionStatusManager {
getTransactionStatus: AccountBridge["getTransactionStatus"] = async (
diff --git a/libs/ledger-live-common/src/families/cosmos/helpers.ts b/libs/coin-modules/coin-cosmos/src/helpers.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/helpers.ts
rename to libs/coin-modules/coin-cosmos/src/helpers.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/helpers.unit.test.ts b/libs/coin-modules/coin-cosmos/src/helpers.unit.test.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/helpers.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/helpers.unit.test.ts
diff --git a/libs/coin-modules/coin-cosmos/src/hw-getAddress.ts b/libs/coin-modules/coin-cosmos/src/hw-getAddress.ts
new file mode 100644
index 000000000000..ffa6466abddb
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/hw-getAddress.ts
@@ -0,0 +1,27 @@
+import { GetAddressFn } from "@ledgerhq/coin-framework/bridge/getAddressWrapper";
+import { GetAddressOptions } from "@ledgerhq/coin-framework/derivation";
+import { SignerContext } from "@ledgerhq/coin-framework/signer";
+import cryptoFactory from "./chain/chain";
+import { CosmosAddress, CosmosSigner } from "./types/signer";
+
+function resolver(signerContext: SignerContext): GetAddressFn {
+ return async (deviceId: string, { path, verify, currency }: GetAddressOptions) => {
+ const cosmosApiImpl = cryptoFactory(currency.id);
+
+ const { address, publicKey } = (await signerContext(deviceId, async signer => {
+ const { address, publicKey } = await signer.getAddress(
+ path,
+ cosmosApiImpl.prefix,
+ verify || false,
+ );
+ return { address, publicKey };
+ })) as CosmosAddress;
+ return {
+ address,
+ publicKey,
+ path,
+ };
+ };
+}
+
+export default resolver;
diff --git a/libs/coin-modules/coin-cosmos/src/logic.ts b/libs/coin-modules/coin-cosmos/src/logic.ts
new file mode 100644
index 000000000000..2d4795119a0b
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/logic.ts
@@ -0,0 +1,196 @@
+import { BigNumber } from "bignumber.js";
+import invariant from "invariant";
+import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies";
+import type { Unit } from "@ledgerhq/types-cryptoassets";
+import type {
+ CosmosAccount,
+ CosmosDelegation,
+ CosmosDelegationInfo,
+ CosmosMappedDelegation,
+ CosmosMappedDelegationInfo,
+ CosmosMappedRedelegation,
+ CosmosMappedUnbonding,
+ CosmosRedelegation,
+ CosmosSearchFilter,
+ CosmosUnbonding,
+ CosmosValidatorItem,
+ Transaction,
+} from "./types";
+
+export const COSMOS_MAX_REDELEGATIONS = 7;
+export const COSMOS_MAX_UNBONDINGS = 7;
+export const COSMOS_MAX_DELEGATIONS = 5;
+export const COSMOS_MIN_SAFE = new BigNumber(100000); // 100000 uAtom
+
+export const COSMOS_MIN_FEES = new BigNumber(6000); // 6000 uAtom
+
+export function mapDelegations(
+ delegations: CosmosDelegation[],
+ validators: CosmosValidatorItem[],
+ unit: Unit,
+): CosmosMappedDelegation[] {
+ return delegations.map(d => {
+ const rank = validators.findIndex(v => v.validatorAddress === d.validatorAddress);
+ const validator = validators[rank] ?? d;
+ return {
+ ...d,
+ formattedAmount: formatCurrencyUnit(unit, d.amount, {
+ disableRounding: false,
+ alwaysShowSign: false,
+ showCode: true,
+ }),
+ formattedPendingRewards: formatCurrencyUnit(unit, d.pendingRewards, {
+ disableRounding: false,
+ alwaysShowSign: false,
+ showCode: true,
+ }),
+ rank,
+ validator,
+ };
+ });
+}
+export function mapUnbondings(
+ unbondings: CosmosUnbonding[],
+ validators: CosmosValidatorItem[],
+ unit: Unit,
+): CosmosMappedUnbonding[] {
+ return unbondings
+ .sort((a, b) => a.completionDate.valueOf() - b.completionDate.valueOf())
+ .map(u => {
+ const validator = validators.find(v => v.validatorAddress === u.validatorAddress);
+ return {
+ ...u,
+ formattedAmount: formatCurrencyUnit(unit, u.amount, {
+ disableRounding: true,
+ alwaysShowSign: false,
+ showCode: true,
+ }),
+ validator,
+ };
+ });
+}
+export function mapRedelegations(
+ redelegations: CosmosRedelegation[],
+ validators: CosmosValidatorItem[],
+ unit: Unit,
+): CosmosMappedRedelegation[] {
+ return redelegations.map(r => {
+ const validatorSrc = validators.find(v => v.validatorAddress === r.validatorSrcAddress);
+ const validatorDst = validators.find(v => v.validatorAddress === r.validatorDstAddress);
+ return {
+ ...r,
+ formattedAmount: formatCurrencyUnit(unit, r.amount, {
+ disableRounding: true,
+ alwaysShowSign: false,
+ showCode: true,
+ }),
+ validatorSrc,
+ validatorDst,
+ };
+ });
+}
+export const mapDelegationInfo = (
+ delegations: CosmosDelegationInfo[],
+ validators: CosmosValidatorItem[],
+ unit: Unit,
+ transaction?: Transaction,
+): CosmosMappedDelegationInfo[] => {
+ return delegations.map(d => ({
+ ...d,
+ validator: validators.find(v => v.validatorAddress === d.address),
+ formattedAmount: formatCurrencyUnit(unit, transaction ? transaction.amount : d.amount, {
+ disableRounding: true,
+ alwaysShowSign: false,
+ showCode: true,
+ }),
+ }));
+};
+export const formatValue = (value: BigNumber, unit: Unit): number =>
+ value
+ .dividedBy(10 ** unit.magnitude)
+ .integerValue(BigNumber.ROUND_FLOOR)
+ .toNumber();
+export const searchFilter: CosmosSearchFilter =
+ query =>
+ ({ validator }) => {
+ const terms = `${validator?.name ?? ""} ${validator?.validatorAddress ?? ""}`;
+ return terms.toLowerCase().includes(query.toLowerCase().trim());
+ };
+export function getMaxDelegationAvailable(
+ account: CosmosAccount,
+ validatorsLength: number,
+): BigNumber {
+ const numberOfDelegations = Math.min(COSMOS_MAX_DELEGATIONS, validatorsLength || 1);
+ const { spendableBalance } = account;
+ return spendableBalance
+ .minus(COSMOS_MIN_FEES.multipliedBy(numberOfDelegations))
+ .minus(COSMOS_MIN_SAFE);
+}
+export const getMaxEstimatedBalance = (a: CosmosAccount, estimatedFees: BigNumber): BigNumber => {
+ const { cosmosResources } = a;
+ let blockBalance = new BigNumber(0);
+
+ if (cosmosResources) {
+ blockBalance = cosmosResources.unbondingBalance.plus(cosmosResources.delegatedBalance);
+ }
+
+ const amount = a.balance.minus(estimatedFees).minus(blockBalance);
+
+ // If the fees are greater than the balance we will have a negative amount
+ // so we round it to 0
+ if (amount.lt(0)) {
+ return new BigNumber(0);
+ }
+
+ return amount;
+};
+
+export function canUndelegate(account: CosmosAccount): boolean {
+ const { cosmosResources } = account;
+ invariant(cosmosResources, "cosmosResources should exist");
+ return !!cosmosResources?.unbondings && cosmosResources.unbondings.length < COSMOS_MAX_UNBONDINGS;
+}
+
+export function canDelegate(account: CosmosAccount): boolean {
+ const maxSpendableBalance = getMaxDelegationAvailable(account, 1);
+ return maxSpendableBalance.gt(0);
+}
+
+export function canRedelegate(
+ account: CosmosAccount,
+ delegation: CosmosDelegation | CosmosValidatorItem,
+): boolean {
+ const { cosmosResources } = account;
+ invariant(cosmosResources, "cosmosResources should exist");
+ return (
+ !!cosmosResources?.redelegations &&
+ cosmosResources.redelegations.length < COSMOS_MAX_REDELEGATIONS &&
+ !cosmosResources.redelegations.some(
+ rd => rd.validatorDstAddress === delegation.validatorAddress,
+ )
+ );
+}
+
+export function getRedelegation(
+ account: CosmosAccount,
+ delegation: CosmosMappedDelegation,
+): CosmosRedelegation | null | undefined {
+ const { cosmosResources } = account;
+ const redelegations = cosmosResources?.redelegations ?? [];
+ const currentRedelegation = redelegations.find(
+ r => r.validatorDstAddress === delegation.validatorAddress,
+ );
+ return currentRedelegation;
+}
+
+export function getRedelegationCompletionDate(
+ account: CosmosAccount,
+ delegation: CosmosMappedDelegation,
+): Date | null | undefined {
+ const currentRedelegation = getRedelegation(account, delegation);
+ return currentRedelegation ? currentRedelegation.completionDate : null;
+}
+
+export function parseAmountStringToNumber(amountString: string, unitCode: string): string {
+ return amountString.slice(amountString.lastIndexOf(",") + 1).replace(unitCode, "");
+}
diff --git a/libs/ledger-live-common/src/families/cosmos/mock.ts b/libs/coin-modules/coin-cosmos/src/mock.ts
similarity index 99%
rename from libs/ledger-live-common/src/families/cosmos/mock.ts
rename to libs/coin-modules/coin-cosmos/src/mock.ts
index 0a49ca091031..f3190be3603d 100644
--- a/libs/ledger-live-common/src/families/cosmos/mock.ts
+++ b/libs/coin-modules/coin-cosmos/src/mock.ts
@@ -1,16 +1,16 @@
-import Prando from "prando";
import { BigNumber } from "bignumber.js";
+import Prando from "prando";
+import { genAddress, genHex } from "@ledgerhq/coin-framework/mocks/helpers";
import type { OperationType } from "@ledgerhq/types-live";
+import preloadedData from "./preloadedData.mock";
import type {
CosmosAccount,
+ CosmosDelegation,
CosmosOperation,
+ CosmosRedelegation,
CosmosResources,
- CosmosDelegation,
CosmosUnbonding,
- CosmosRedelegation,
} from "./types";
-import preloadedData from "./preloadedData.mock";
-import { genHex, genAddress } from "../../mock/helpers";
const { validators } = preloadedData;
function setCosmosResources(
diff --git a/libs/ledger-live-common/src/families/cosmos/preloadedData.mock.ts b/libs/coin-modules/coin-cosmos/src/preloadedData.mock.ts
similarity index 99%
rename from libs/ledger-live-common/src/families/cosmos/preloadedData.mock.ts
rename to libs/coin-modules/coin-cosmos/src/preloadedData.mock.ts
index 82ca08fef288..91a32a2dc2ef 100644
--- a/libs/ledger-live-common/src/families/cosmos/preloadedData.mock.ts
+++ b/libs/coin-modules/coin-cosmos/src/preloadedData.mock.ts
@@ -1,6 +1,9 @@
import type { CosmosPreloadData } from "./types";
-import { liveConfig } from "../../config/sharedConfig";
-const LEDGER_VALIDATOR_ADDRESS = liveConfig["config_currency_cosmos"].default["ledgerValidator"];
+import { cosmosConfig } from "./config";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const LEDGER_VALIDATOR_ADDRESS = cosmosConfig.config_currency_cosmos.default["ledgerValidator"];
// Data manually fetched from the network between heights
// 1685677 and 1685679
const data: CosmosPreloadData = {
diff --git a/libs/ledger-live-common/src/families/cosmos/preloadedData.ts b/libs/coin-modules/coin-cosmos/src/preloadedData.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/preloadedData.ts
rename to libs/coin-modules/coin-cosmos/src/preloadedData.ts
diff --git a/libs/ledger-live-common/src/families/cosmos/prepareTransaction.ts b/libs/coin-modules/coin-cosmos/src/prepareTransaction.ts
similarity index 98%
rename from libs/ledger-live-common/src/families/cosmos/prepareTransaction.ts
rename to libs/coin-modules/coin-cosmos/src/prepareTransaction.ts
index a133b0b8313a..9b66cba7ce03 100644
--- a/libs/ledger-live-common/src/families/cosmos/prepareTransaction.ts
+++ b/libs/coin-modules/coin-cosmos/src/prepareTransaction.ts
@@ -1,11 +1,11 @@
+import BigNumber from "bignumber.js";
+import { getEnv } from "@ledgerhq/live-env";
import { CacheRes, makeLRUCache } from "@ledgerhq/live-network/cache";
import { log } from "@ledgerhq/logs";
import type { Account, AccountBridge } from "@ledgerhq/types-live";
-import BigNumber from "bignumber.js";
-import { getEnv } from "@ledgerhq/live-env";
import { CosmosAPI } from "./api/Cosmos";
+import { buildTransaction, txToMessages } from "./buildTransaction";
import cryptoFactory from "./chain/chain";
-import { txToMessages, buildTransaction } from "./buildTransaction";
import { getMaxEstimatedBalance } from "./logic";
import { CosmosAccount, Transaction } from "./types";
diff --git a/libs/ledger-live-common/src/families/cosmos/prepareTransaction.unit.test.ts b/libs/coin-modules/coin-cosmos/src/prepareTransaction.unit.test.ts
similarity index 97%
rename from libs/ledger-live-common/src/families/cosmos/prepareTransaction.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/prepareTransaction.unit.test.ts
index 185cf14cdbd5..b22b81ef05b3 100644
--- a/libs/ledger-live-common/src/families/cosmos/prepareTransaction.unit.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/prepareTransaction.unit.test.ts
@@ -1,11 +1,9 @@
+import BigNumber from "bignumber.js";
import network from "@ledgerhq/live-network/network";
import { CryptoCurrencyId } from "@ledgerhq/types-cryptoassets";
-import BigNumber from "bignumber.js";
import * as jsPrepareTransaction from "./prepareTransaction";
import { calculateFees, getEstimatedFees } from "./prepareTransaction";
import { CosmosAccount, Transaction } from "./types";
-import { LiveConfig } from "@ledgerhq/live-config/LiveConfig";
-import { liveConfig } from "../../config/sharedConfig";
jest.mock("@ledgerhq/live-network/network");
@@ -23,8 +21,6 @@ const transaction = {
useAllAmount: false,
} as unknown as Transaction;
-LiveConfig.setConfig(liveConfig);
-
describe("getEstimatedFees", () => {
it("should return gas higher than estimate", async () => {
const gasSimulationMock = 42000;
diff --git a/libs/ledger-live-common/src/families/cosmos/serialization.ts b/libs/coin-modules/coin-cosmos/src/serialization.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/serialization.ts
rename to libs/coin-modules/coin-cosmos/src/serialization.ts
index e24efed73e5c..f2909491e37b 100644
--- a/libs/ledger-live-common/src/families/cosmos/serialization.ts
+++ b/libs/coin-modules/coin-cosmos/src/serialization.ts
@@ -1,14 +1,14 @@
import { BigNumber } from "bignumber.js";
+import { Account, AccountRaw, OperationExtra, OperationExtraRaw } from "@ledgerhq/types-live";
import {
- type CosmosResourcesRaw,
- type CosmosResources,
- type CosmosAccountRaw,
- type CosmosAccount,
- isCosmosOperationExtraRaw,
CosmosOperationExtra,
CosmosOperationExtraRaw,
+ isCosmosOperationExtraRaw,
+ type CosmosAccount,
+ type CosmosAccountRaw,
+ type CosmosResources,
+ type CosmosResourcesRaw,
} from "./types";
-import { Account, AccountRaw, OperationExtra, OperationExtraRaw } from "@ledgerhq/types-live";
export function toCosmosResourcesRaw(r: CosmosResources): CosmosResourcesRaw {
const {
diff --git a/libs/coin-modules/coin-cosmos/src/signOperation.ts b/libs/coin-modules/coin-cosmos/src/signOperation.ts
new file mode 100644
index 000000000000..256c173ed764
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/signOperation.ts
@@ -0,0 +1,180 @@
+import BigNumber from "bignumber.js";
+import { Observable } from "rxjs";
+import { makeSignDoc, serializeSignDoc } from "@cosmjs/amino";
+import { Secp256k1Signature } from "@cosmjs/crypto";
+import { Coin } from "@keplr-wallet/proto-types/cosmos/base/v1beta1/coin";
+import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
+import { SignerContext } from "@ledgerhq/coin-framework/signer";
+import { ExpertModeRequired, UserRefusedOnDevice } from "@ledgerhq/errors";
+import type { AccountBridge, Operation, OperationType } from "@ledgerhq/types-live";
+import { CosmosAPI } from "./api/Cosmos";
+import { buildTransaction, txToMessages } from "./buildTransaction";
+import cryptoFactory from "./chain/chain";
+import { CosmosAccount, RETURN_CODES, Transaction } from "./types";
+import { CosmosSignatureSdk, CosmosSigner } from "./types/signer";
+
+export const buildSignOperation =
+ (
+ signerContext: SignerContext,
+ ): AccountBridge["signOperation"] =>
+ ({ account, deviceId, transaction }) =>
+ new Observable(o => {
+ let cancelled: boolean;
+ async function main() {
+ const cosmosAPI = new CosmosAPI(account.currency.id);
+ const chainInstance = cryptoFactory(account.currency.id);
+
+ const { accountNumber, sequence, pubKeyType } = await cosmosAPI.getAccount(
+ account.freshAddress,
+ );
+ o.next({ type: "device-signature-requested" });
+ const { aminoMsgs, protoMsgs } = txToMessages(account, transaction);
+ if (transaction.fees == null || transaction.gas == null) {
+ throw new Error("Transaction misses gas information");
+ }
+ const feeToEncode = {
+ amount: [
+ {
+ denom: account.currency.units[1].code,
+ amount: transaction.fees.toFixed(),
+ },
+ ],
+ gas: transaction.gas.toFixed(),
+ };
+ // Note:
+ // Cosmos Nano App sign data in Amino way only, not Protobuf.
+ // This is a legacy outdated standard and a long-term blocking point.
+ const chainId = (await cosmosAPI.getNodeInfo()).default_node_info.network;
+ const signDoc = makeSignDoc(
+ aminoMsgs,
+ feeToEncode,
+ chainId,
+ transaction.memo || "",
+ accountNumber.toString(),
+ sequence.toString(),
+ );
+ const tx = Buffer.from(serializeSignDoc(signDoc));
+ const path = account.freshAddressPath.split("/").map(p => parseInt(p.replace("'", "")));
+
+ const { compressed_pk } = await signerContext(deviceId, signer =>
+ signer.getAddressAndPubKey(path, chainInstance.prefix, false),
+ );
+ const pubKey = Buffer.from(compressed_pk).toString("base64");
+
+ const { signature: resSignature, return_code } = (await signerContext(
+ deviceId,
+ async signer => {
+ let res;
+ // HRP is only needed when signing for ethermint chains
+ if (path[1] === 60) {
+ res = await signer.sign(path, tx, chainInstance.prefix);
+ } else {
+ res = await signer.sign(path, tx);
+ }
+ return res;
+ },
+ )) as CosmosSignatureSdk;
+
+ switch (return_code) {
+ case RETURN_CODES.EXPERT_MODE_REQUIRED:
+ throw new ExpertModeRequired();
+ case RETURN_CODES.REFUSED_OPERATION:
+ throw new UserRefusedOnDevice();
+ }
+
+ const signature = Buffer.from(Secp256k1Signature.fromDer(resSignature).toFixedLength());
+
+ const txBytes = buildTransaction({
+ protoMsgs,
+ memo: transaction.memo || "",
+ pubKeyType,
+ pubKey,
+ feeAmount: signDoc.fee.amount as Coin[],
+ gasLimit: signDoc.fee.gas,
+ sequence: signDoc.sequence,
+ signature,
+ });
+
+ const signed = Buffer.from(txBytes).toString("hex");
+
+ if (cancelled) {
+ return;
+ }
+
+ o.next({ type: "device-signature-granted" });
+
+ const hash = ""; // resolved at broadcast time
+ const accountId = account.id;
+ const fee = transaction.fees || new BigNumber(0);
+ const extra = {};
+
+ const type: OperationType =
+ transaction.mode === "undelegate"
+ ? "UNDELEGATE"
+ : transaction.mode === "delegate"
+ ? "DELEGATE"
+ : transaction.mode === "redelegate"
+ ? "REDELEGATE"
+ : ["claimReward", "claimRewardCompound"].includes(transaction.mode)
+ ? "REWARD"
+ : "OUT";
+
+ const senders: string[] = [];
+ const recipients: string[] = [];
+
+ if (transaction.mode === "send") {
+ senders.push(account.freshAddress);
+ recipients.push(transaction.recipient);
+ }
+
+ if (transaction.mode === "redelegate") {
+ Object.assign(extra, {
+ sourceValidator: transaction.sourceValidator,
+ });
+ }
+
+ if (transaction.mode !== "send") {
+ Object.assign(extra, {
+ validators: transaction.validators,
+ });
+ }
+
+ // build optimistic operation
+ const operation: Operation = {
+ id: encodeOperationId(accountId, hash, type),
+ hash,
+ type,
+ value:
+ type === "REWARD"
+ ? new BigNumber(0)
+ : transaction.useAllAmount
+ ? account.spendableBalance
+ : transaction.amount.plus(fee),
+ fee,
+ extra,
+ blockHash: null,
+ blockHeight: null,
+ senders,
+ recipients,
+ accountId,
+ date: new Date(),
+ transactionSequenceNumber: sequence,
+ };
+
+ o.next({
+ type: "signed",
+ signedOperation: {
+ operation,
+ signature: signed,
+ },
+ });
+ }
+ main().then(
+ () => o.complete(),
+ e => o.error(e),
+ );
+
+ return () => {
+ cancelled = true;
+ };
+ });
diff --git a/libs/ledger-live-common/src/families/cosmos/specs.ts b/libs/coin-modules/coin-cosmos/src/specs.ts
similarity index 98%
rename from libs/ledger-live-common/src/families/cosmos/specs.ts
rename to libs/coin-modules/coin-cosmos/src/specs.ts
index 43b24fb16a1f..4fda6693b83c 100644
--- a/libs/ledger-live-common/src/families/cosmos/specs.ts
+++ b/libs/coin-modules/coin-cosmos/src/specs.ts
@@ -1,35 +1,35 @@
-import { DeviceModelId } from "@ledgerhq/devices";
+import { BigNumber } from "bignumber.js";
import expect from "expect";
import invariant from "invariant";
import sample from "lodash/sample";
import sampleSize from "lodash/sampleSize";
-import { toOperationRaw } from "../../account";
import {
botTest,
expectSiblingsHaveSpendablePartGreaterThan,
genericTestDestination,
pickSiblings,
SpeculosButton,
-} from "../../bot/specs";
-import type { AppSpec, MutationSpec } from "../../bot/types";
-import { getCryptoCurrencyById } from "../../currencies";
-import { getCurrentCosmosPreloadData } from "../../families/cosmos/preloadedData";
+} from "@ledgerhq/coin-framework/bot/specs";
+import type { AppSpec, MutationSpec } from "@ledgerhq/coin-framework/bot/types";
+import { toOperationRaw } from "@ledgerhq/coin-framework/serialization";
+import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
+import { DeviceModelId } from "@ledgerhq/devices";
+import { log } from "@ledgerhq/logs";
+import { Operation } from "@ledgerhq/types-live";
+import { canDelegate, canRedelegate, canUndelegate, getMaxDelegationAvailable } from "./logic";
+import { getCurrentCosmosPreloadData } from "./preloadedData";
+import { acceptTransaction } from "./speculos-deviceActions";
import type {
CosmosAccount,
CosmosDelegation,
- CosmosOperationExtraRaw,
CosmosDelegationInfoRaw,
+ CosmosOperationExtraRaw,
+ CosmosOperationRaw,
CosmosRedelegation,
CosmosResources,
CosmosUnbonding,
Transaction,
- CosmosOperationRaw,
-} from "../../families/cosmos/types";
-import { canDelegate, canRedelegate, canUndelegate, getMaxDelegationAvailable } from "./logic";
-import { acceptTransaction } from "./speculos-deviceActions";
-import { Operation } from "@ledgerhq/types-live";
-import { BigNumber } from "bignumber.js";
-import { log } from "@ledgerhq/logs";
+} from "./types";
const maxAccounts = 16;
@@ -447,7 +447,7 @@ const generateGenericCosmosTest = (
testTimeout: 2 * 60 * 1000,
test: cosmosLikeTest,
onSpeculosDeviceCreated: isExpertModeRequired
- ? async ({ transport }) => {
+ ? async ({ transport }: { transport: any }) => {
await transport.button(SpeculosButton.RIGHT);
await transport.button(SpeculosButton.BOTH);
}
diff --git a/libs/ledger-live-common/src/families/cosmos/speculos-deviceActions.ts b/libs/coin-modules/coin-cosmos/src/speculos-deviceActions.ts
similarity index 88%
rename from libs/ledger-live-common/src/families/cosmos/speculos-deviceActions.ts
rename to libs/coin-modules/coin-cosmos/src/speculos-deviceActions.ts
index 5ad36621037b..11f08212f347 100644
--- a/libs/ledger-live-common/src/families/cosmos/speculos-deviceActions.ts
+++ b/libs/coin-modules/coin-cosmos/src/speculos-deviceActions.ts
@@ -1,6 +1,7 @@
-import type { DeviceAction } from "../../bot/types";
-import { deviceActionFlow, SpeculosButton } from "../../bot/specs";
+import type { DeviceAction, State } from "@ledgerhq/coin-framework/bot/types";
+import { deviceActionFlow, SpeculosButton } from "@ledgerhq/coin-framework/bot/specs";
import type { Transaction } from "./types";
+
const typeWording = {
send: "Send",
delegate: "Delegate",
@@ -10,7 +11,7 @@ const typeWording = {
claimRewardCompound: "(not tested)",
};
-export const acceptTransaction: DeviceAction = deviceActionFlow({
+export const acceptTransaction: DeviceAction> = deviceActionFlow({
steps: [
{
title: "Sequence",
diff --git a/libs/ledger-live-common/src/families/cosmos/synchronisation.ts b/libs/coin-modules/coin-cosmos/src/synchronisation.ts
similarity index 94%
rename from libs/ledger-live-common/src/families/cosmos/synchronisation.ts
rename to libs/coin-modules/coin-cosmos/src/synchronisation.ts
index 7ee3e8d9c5db..b9f667df9f69 100644
--- a/libs/ledger-live-common/src/families/cosmos/synchronisation.ts
+++ b/libs/coin-modules/coin-cosmos/src/synchronisation.ts
@@ -1,20 +1,18 @@
import { BigNumber } from "bignumber.js";
+import { encodeAccountId } from "@ledgerhq/coin-framework/account";
import {
- makeSync,
- makeScanAccounts,
+ AccountShapeInfo,
GetAccountShape,
mergeOps,
- AccountShapeInfo,
-} from "../../bridge/jsHelpers";
-import { encodeAccountId } from "../../account";
-import { CosmosAPI } from "./api/Cosmos";
-import { encodeOperationId } from "../../operation";
-import { CosmosAccount, CosmosOperation, CosmosTx } from "./types";
+} from "@ledgerhq/coin-framework/bridge/jsHelpers";
+import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
import type { OperationType } from "@ledgerhq/types-live";
+import { CosmosAPI } from "./api/Cosmos";
import { getMainMessage } from "./helpers";
import { parseAmountStringToNumber } from "./logic";
+import { CosmosAccount, CosmosOperation, CosmosTx } from "./types";
-export const getAccountShape: GetAccountShape = async info => {
+export const getAccountShape: GetAccountShape = async (info: any) => {
const { address, currency, derivationMode, initialAccount } = info;
const accountId = encodeAccountId({
type: "js",
@@ -87,9 +85,6 @@ export const getAccountShape: GetAccountShape = async info => {
return { ...shape, operations };
};
-export const scanAccounts = makeScanAccounts({ getAccountShape });
-export const sync = makeSync({ getAccountShape });
-
const getBlankOperation = (tx: CosmosTx, fees: BigNumber, accountId: string): CosmosOperation => {
return {
id: "",
@@ -129,7 +124,7 @@ const txToOps = (info: AccountShapeInfo, accountId: string, txs: CosmosTx[]): Co
op.hasFailed = tx.code !== 0;
// simplify the message types
- const messages = tx.tx.body.messages.map(message => ({
+ const messages = tx.tx.body.messages.map((message: any) => ({
...message,
type: message["@type"].substring(message["@type"].lastIndexOf(".") + 1),
}));
@@ -140,7 +135,7 @@ const txToOps = (info: AccountShapeInfo, accountId: string, txs: CosmosTx[]): Co
continue;
}
- const correspondingMessages = messages.filter(m => m.type === mainMessage.type);
+ const correspondingMessages = messages.filter((m: any) => m.type === mainMessage.type);
switch (mainMessage.type) {
case "MsgTransfer": {
@@ -186,7 +181,7 @@ const txToOps = (info: AccountShapeInfo, accountId: string, txs: CosmosTx[]): Co
}
case "MsgSend": {
for (const message of correspondingMessages) {
- const amount = message["amount"].find(amount => amount.denom === unitCode);
+ const amount = message["amount"].find((amount: any) => amount.denom === unitCode);
const sender = message["from_address"];
const recipient = message["to_address"];
if (!amount || !sender || !recipient) {
diff --git a/libs/ledger-live-common/src/families/cosmos/synchronisation.unit.test.ts b/libs/coin-modules/coin-cosmos/src/synchronisation.unit.test.ts
similarity index 98%
rename from libs/ledger-live-common/src/families/cosmos/synchronisation.unit.test.ts
rename to libs/coin-modules/coin-cosmos/src/synchronisation.unit.test.ts
index c6f5c4d9ca92..3e3d2c196525 100644
--- a/libs/ledger-live-common/src/families/cosmos/synchronisation.unit.test.ts
+++ b/libs/coin-modules/coin-cosmos/src/synchronisation.unit.test.ts
@@ -1,15 +1,15 @@
+import BigNumber from "bignumber.js";
+import * as jsHelpers from "@ledgerhq/coin-framework/bridge/jsHelpers";
+import { AccountShapeInfo } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import { CryptoCurrency } from "@ledgerhq/types-cryptoassets";
import { Operation, SyncConfig } from "@ledgerhq/types-live";
-import BigNumber from "bignumber.js";
-import { AccountShapeInfo } from "../../bridge/jsHelpers";
import { CosmosAPI } from "./api/Cosmos";
import { getAccountShape } from "./synchronisation";
import { CosmosAccount, CosmosOperation, CosmosTx } from "./types";
-import * as jsHelpers from "../../bridge/jsHelpers";
jest.mock("./api/Cosmos");
-jest.mock("../../account");
-jest.mock("../../bridge/jsHelpers");
+jest.mock("@ledgerhq/coin-framework/account");
+jest.mock("@ledgerhq/coin-framework/bridge/jsHelpers");
const infoMock = {
currency: {
diff --git a/libs/ledger-live-common/src/families/cosmos/transaction.ts b/libs/coin-modules/coin-cosmos/src/transaction.ts
similarity index 94%
rename from libs/ledger-live-common/src/families/cosmos/transaction.ts
rename to libs/coin-modules/coin-cosmos/src/transaction.ts
index 58f0dbdeb744..153b94ba9a84 100644
--- a/libs/ledger-live-common/src/families/cosmos/transaction.ts
+++ b/libs/coin-modules/coin-cosmos/src/transaction.ts
@@ -1,5 +1,6 @@
import { BigNumber } from "bignumber.js";
-import type { Transaction, TransactionRaw } from "./types";
+import { getAccountCurrency } from "@ledgerhq/coin-framework/account/index";
+import { formatCurrencyUnit } from "@ledgerhq/coin-framework/currencies/index";
import { formatTransactionStatus } from "@ledgerhq/coin-framework/formatters";
import {
fromTransactionCommonRaw,
@@ -7,9 +8,8 @@ import {
toTransactionCommonRaw,
toTransactionStatusRawCommon as toTransactionStatusRaw,
} from "@ledgerhq/coin-framework/serialization";
-import { getAccountCurrency } from "../../account";
-import { formatCurrencyUnit } from "../../currencies";
import { Account } from "@ledgerhq/types-live";
+import type { Transaction, TransactionRaw } from "./types";
export const formatTransaction = (
{ mode, amount, fees, recipient, validators, memo, sourceValidator, useAllAmount }: Transaction,
diff --git a/libs/coin-modules/coin-cosmos/src/types/index.ts b/libs/coin-modules/coin-cosmos/src/types/index.ts
new file mode 100644
index 000000000000..e60f921ecaa3
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/types/index.ts
@@ -0,0 +1,306 @@
+import type { BigNumber } from "bignumber.js";
+import {
+ Account,
+ AccountRaw,
+ Operation,
+ OperationExtra,
+ OperationExtraRaw,
+ OperationRaw,
+ TransactionCommon,
+ TransactionCommonRaw,
+ TransactionStatusCommon,
+ TransactionStatusCommonRaw,
+} from "@ledgerhq/types-live";
+
+export type CosmosDelegationStatus =
+ | "bonded" // in the active set that generates rewards
+ | "unbonding" // doesn't generate rewards. means the validator has been removed from the active set, but has its voting power "frozen" in case they misbehaved (just like a delegator undelegating). This last 21 days
+ | "unbonded";
+// doesn't generate rewards. means the validator has been removed from the active set for more than 21 days basically
+export type CosmosDelegation = {
+ validatorAddress: string;
+ amount: BigNumber;
+ pendingRewards: BigNumber;
+ status: CosmosDelegationStatus;
+};
+export type CosmosRedelegation = {
+ validatorSrcAddress: string;
+ validatorDstAddress: string;
+ amount: BigNumber;
+ completionDate: Date;
+};
+export type CosmosUnbonding = {
+ validatorAddress: string;
+ amount: BigNumber;
+ completionDate: Date;
+};
+
+export type CosmosTx = {
+ code: number;
+ codespace: string;
+ data: string;
+ events: CosmosMessage[];
+ gas_used: string;
+ gas_wanted: string;
+ height: string;
+ info: string;
+ logs: any[];
+ raw_log: string;
+ timestamp: string;
+ tx: { "@type": string; body: any; auth_info: any; signatures: any[] };
+ txhash: string;
+};
+
+export type CosmosMessage = {
+ type: string;
+ attributes: { key: string; value: string; index?: boolean }[];
+};
+
+export type CosmosResources = {
+ delegations: CosmosDelegation[];
+ redelegations: CosmosRedelegation[];
+ unbondings: CosmosUnbonding[];
+ delegatedBalance: BigNumber;
+ pendingRewardsBalance: BigNumber;
+ unbondingBalance: BigNumber;
+ withdrawAddress: string;
+ sequence: number;
+};
+export type CosmosDelegationRaw = {
+ validatorAddress: string;
+ amount: string;
+ pendingRewards: string;
+ status: CosmosDelegationStatus;
+};
+export type CosmosUnbondingRaw = {
+ validatorAddress: string;
+ amount: string;
+ completionDate: string;
+};
+export type CosmosRedelegationRaw = {
+ validatorSrcAddress: string;
+ validatorDstAddress: string;
+ amount: string;
+ completionDate: string;
+};
+export type CosmosResourcesRaw = {
+ delegations: CosmosDelegationRaw[];
+ redelegations: CosmosRedelegationRaw[];
+ unbondings: CosmosUnbondingRaw[];
+ delegatedBalance: string;
+ pendingRewardsBalance: string;
+ unbondingBalance: string;
+ withdrawAddress: string;
+ sequence: number;
+};
+// NB this must be serializable (no Date, no BigNumber)
+export type CosmosValidatorItem = {
+ validatorAddress: string;
+ name: string;
+ votingPower: number;
+ // value from 0.0 to 1.0 (normalized percentage)
+ commission: number;
+ // value from 0.0 to 1.0 (normalized percentage)
+ estimatedYearlyRewardsRate: number; // value from 0.0 to 1.0 (normalized percentage)
+ tokens: number;
+};
+// by convention preload would return a Promise of CosmosPreloadData
+export type CosmosPreloadData = {
+ validators: CosmosValidatorItem[];
+};
+export type CosmosOperationMode =
+ | "send"
+ | "delegate"
+ | "undelegate"
+ | "redelegate"
+ | "claimReward"
+ | "claimRewardCompound";
+
+export type CosmosLikeNetworkInfo = {
+ family: string;
+ fees: BigNumber;
+};
+
+export type CosmosLikeNetworkInfoRaw = {
+ family: string;
+ fees: string;
+};
+
+export type NetworkInfo = CosmosLikeNetworkInfo & {
+ family: "cosmos";
+};
+
+export type NetworkInfoRaw = CosmosLikeNetworkInfoRaw & {
+ family: "cosmos";
+};
+
+export type CosmosOperation = Operation;
+export type CosmosOperationRaw = OperationRaw;
+
+export type CosmosOperationExtra = OperationExtra & {
+ validators?: CosmosDelegationInfo[];
+ validator?: CosmosDelegationInfo;
+ sourceValidator?: string;
+ autoClaimedRewards?: string; // this is experimental to better represent auto claimed rewards
+ memo?: string;
+};
+export function isCosmosOperationExtra(op: OperationExtra): op is CosmosOperationExtra {
+ return (
+ op !== null &&
+ typeof op === "object" &&
+ ("validators" in op ||
+ "validator" in op ||
+ "sourceValidator" in op ||
+ "autoClaimedRewards" in op ||
+ "memo" in op)
+ );
+}
+
+export type CosmosOperationExtraRaw = OperationExtraRaw & {
+ validators?: CosmosDelegationInfoRaw[];
+ validator?: CosmosDelegationInfoRaw;
+ sourceValidator?: string;
+ autoClaimedRewards?: string; // this is experimental to better represent auto claimed rewards
+ memo?: string;
+};
+export function isCosmosOperationExtraRaw(op: OperationExtraRaw): op is CosmosOperationExtraRaw {
+ return (
+ op !== null &&
+ typeof op === "object" &&
+ ("validators" in op ||
+ "validator" in op ||
+ "sourceValidator" in op ||
+ "autoClaimedRewards" in op ||
+ "memo" in op)
+ );
+}
+
+export type CosmosDelegationInfo = {
+ address: string;
+ amount: BigNumber;
+};
+
+export type CosmosDelegationInfoRaw = {
+ address: string;
+ amount: string;
+};
+
+export type CosmosLikeTransaction = TransactionCommon & {
+ family: string;
+ mode: CosmosOperationMode;
+ networkInfo: CosmosLikeNetworkInfo | null | undefined;
+ fees: BigNumber | null | undefined;
+ gas: BigNumber | null | undefined;
+ memo: string | null | undefined;
+ validators: CosmosDelegationInfo[];
+ sourceValidator: string | null | undefined;
+};
+
+export type Transaction = CosmosLikeTransaction & {
+ family: "cosmos";
+ networkInfo: NetworkInfo | null | undefined;
+};
+
+export type CosmosLikeTransactionRaw = TransactionCommonRaw & {
+ family: string;
+ mode: CosmosOperationMode;
+ networkInfo: CosmosLikeNetworkInfoRaw | null | undefined;
+ fees: string | null | undefined;
+ gas: string | null | undefined;
+ memo: string | null | undefined;
+ validators: CosmosDelegationInfoRaw[];
+ sourceValidator: string | null | undefined;
+};
+
+export type TransactionRaw = CosmosLikeTransactionRaw & {
+ family: "cosmos";
+ networkInfo: NetworkInfoRaw | null | undefined;
+};
+
+export type StatusErrorMap = {
+ recipient?: Error;
+ amount?: Error;
+ fees?: Error;
+ validators?: Error;
+ delegate?: Error;
+ redelegation?: Error;
+ unbonding?: Error;
+ claimReward?: Error;
+ feeTooHigh?: Error;
+};
+
+export type CosmosMappedDelegation = CosmosDelegation & {
+ formattedAmount: string;
+ formattedPendingRewards: string;
+ rank: number;
+ validator: CosmosValidatorItem | null | undefined;
+};
+export type CosmosMappedUnbonding = CosmosUnbonding & {
+ formattedAmount: string;
+ validator: CosmosValidatorItem | null | undefined;
+};
+export type CosmosMappedRedelegation = CosmosRedelegation & {
+ formattedAmount: string;
+ validatorSrc: CosmosValidatorItem | null | undefined;
+ validatorDst: CosmosValidatorItem | null | undefined;
+};
+export type CosmosMappedDelegationInfo = CosmosDelegationInfo & {
+ validator: CosmosValidatorItem | null | undefined;
+ formattedAmount: string;
+};
+export type CosmosMappedValidator = {
+ rank: number;
+ validator: CosmosValidatorItem;
+};
+export type CosmosSearchFilter = (
+ query: string,
+) => (delegation: CosmosMappedDelegation | CosmosMappedValidator) => boolean;
+export type CosmosAccount = Account & { cosmosResources: CosmosResources };
+export type CosmosAccountRaw = AccountRaw & {
+ cosmosResources: CosmosResourcesRaw;
+};
+export type TransactionStatus = TransactionStatusCommon;
+
+export type TransactionStatusRaw = TransactionStatusCommonRaw;
+
+export type CosmosTotalSupply = {
+ denom: string;
+ amount: string;
+};
+
+export type CosmosPool = {
+ not_bonded_tokens: string;
+ bonded_tokens: string;
+};
+
+export type CosmosDistributionParams = {
+ community_tax: string;
+ base_proposer_reward: string;
+ bonus_proposer_reward: string;
+ withdraw_addr_enabled: boolean;
+};
+
+export type CosmosCurrencyConfig = {
+ lcd: string;
+ minGasPrice: number;
+ ledgerValidator?: string;
+};
+
+export const RETURN_CODES = {
+ EXPERT_MODE_REQUIRED: 27012,
+ REFUSED_OPERATION: 27014,
+};
+
+// NOTE: didn't follow what was in libs/ledgerjs/packages/hw-app-cosmos/src/Cosmos.ts
+export interface CosmosSignerOld {
+ getAddress(
+ path: string,
+ chainPrefix: number,
+ verify: boolean,
+ ): Promise<{ address: any; publicKey: any }>;
+ sign(
+ path: string,
+ tx: Uint8Array,
+ chainPrefix?: string,
+ ): Promise<{ return_code: any; signature: any }>;
+}
diff --git a/libs/coin-modules/coin-cosmos/src/types/signer.ts b/libs/coin-modules/coin-cosmos/src/types/signer.ts
new file mode 100644
index 000000000000..6d9042476dce
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/src/types/signer.ts
@@ -0,0 +1,32 @@
+export type CosmosAddress = {
+ publicKey: string;
+ address: string;
+};
+
+export type CosmosGetAddressAndPubKeyRes = {
+ bech32_address: string;
+ compressed_pk: string;
+ return_code: number;
+ error_message: string;
+};
+
+export type CosmosSignature = {
+ signature: null | Buffer;
+ return_code: number | string;
+};
+
+export type CosmosSignatureSdk = {
+ signature: Uint8Array;
+ return_code: number | string;
+};
+
+export interface CosmosSigner {
+ getAddressAndPubKey(
+ path: number[],
+ hrp: string,
+ boolDisplay?: boolean,
+ ): Promise;
+ sign(path: number[], buffer: Buffer, transactionType?: string): Promise;
+ // NOTE: explain this one, to support cosmos-like chains (hw-app-cosmos)
+ getAddress(path: string, hrp: string, boolDisplay?: boolean): Promise;
+}
diff --git a/libs/ledger-live-common/src/families/cosmos/updateTransaction.ts b/libs/coin-modules/coin-cosmos/src/updateTransaction.ts
similarity index 100%
rename from libs/ledger-live-common/src/families/cosmos/updateTransaction.ts
rename to libs/coin-modules/coin-cosmos/src/updateTransaction.ts
index 820bcd3008dd..30415d8f43ef 100644
--- a/libs/ledger-live-common/src/families/cosmos/updateTransaction.ts
+++ b/libs/coin-modules/coin-cosmos/src/updateTransaction.ts
@@ -1,6 +1,6 @@
+import { defaultUpdateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
import { AccountBridge } from "@ledgerhq/types-live";
import { Transaction } from "./types";
-import { defaultUpdateTransaction } from "@ledgerhq/coin-framework/bridge/jsHelpers";
export const updateTransaction: AccountBridge["updateTransaction"] = (tx, patch) => {
if (
diff --git a/libs/coin-modules/coin-cosmos/tsconfig.json b/libs/coin-modules/coin-cosmos/tsconfig.json
new file mode 100644
index 000000000000..f56b01ccd35e
--- /dev/null
+++ b/libs/coin-modules/coin-cosmos/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../../../tsconfig.base",
+ "compilerOptions": {
+ "declaration": true,
+ "declarationMap": true,
+ "module": "commonjs",
+ "downlevelIteration": true,
+ "lib": ["es2020", "dom"],
+ "outDir": "lib",
+ "exactOptionalPropertyTypes": true
+ },
+ "include": ["src/**/*"]
+}
diff --git a/libs/coin-modules/coin-evm/CHANGELOG.md b/libs/coin-modules/coin-evm/CHANGELOG.md
index 10b776fcdf3a..b443c3764f98 100644
--- a/libs/coin-modules/coin-evm/CHANGELOG.md
+++ b/libs/coin-modules/coin-evm/CHANGELOG.md
@@ -1,5 +1,57 @@
# @ledgerhq/coin-evm
+## 2.2.0
+
+### Minor Changes
+
+- [#7741](https://github.com/LedgerHQ/ledger-live/pull/7741) [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037) Thanks [@CremaFR](https://github.com/CremaFR)! - fixed bnb custom fee crashes and erased gasLimit
+
+- [#7652](https://github.com/LedgerHQ/ledger-live/pull/7652) [`e7db725`](https://github.com/LedgerHQ/ledger-live/commit/e7db72552042ff4dd85bec236f6bd083fa3da533) Thanks [@CremaFR](https://github.com/CremaFR)! - fix evm getFeeData to return requested option value
+
+### Patch Changes
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7531](https://github.com/LedgerHQ/ledger-live/pull/7531) [`d213d81`](https://github.com/LedgerHQ/ledger-live/commit/d213d8122647d559b7a0f44e2beffa5e39c3249b) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Remove `NotEnoughBalanceInParentAccount` error from `validateAmount` check in `getTransactionStatus` as it was redundant with a `validateGas` test
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/domain-service@1.2.4
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/evm-tools@1.2.1
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/devices@8.4.3
+
+## 2.2.0-next.0
+
+### Minor Changes
+
+- [#7741](https://github.com/LedgerHQ/ledger-live/pull/7741) [`224e33c`](https://github.com/LedgerHQ/ledger-live/commit/224e33c93d2acd22c82892148b240df004284037) Thanks [@CremaFR](https://github.com/CremaFR)! - fixed bnb custom fee crashes and erased gasLimit
+
+- [#7652](https://github.com/LedgerHQ/ledger-live/pull/7652) [`e7db725`](https://github.com/LedgerHQ/ledger-live/commit/e7db72552042ff4dd85bec236f6bd083fa3da533) Thanks [@CremaFR](https://github.com/CremaFR)! - fix evm getFeeData to return requested option value
+
+### Patch Changes
+
+- [#7593](https://github.com/LedgerHQ/ledger-live/pull/7593) [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Update `axios` to fixed version `1.7.3`
+
+- [#7710](https://github.com/LedgerHQ/ledger-live/pull/7710) [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Migrating the Matic currency to POL (see https://polygon.technology/blog/save-the-date-matic-pol-migration-coming-september-4th-everything-you-need-to-know)
+
+- [#7531](https://github.com/LedgerHQ/ledger-live/pull/7531) [`d213d81`](https://github.com/LedgerHQ/ledger-live/commit/d213d8122647d559b7a0f44e2beffa5e39c3249b) Thanks [@lambertkevin](https://github.com/lambertkevin)! - Remove `NotEnoughBalanceInParentAccount` error from `validateAmount` check in `getTransactionStatus` as it was redundant with a `validateGas` test
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/domain-service@1.2.4-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/evm-tools@1.2.1-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 2.1.4
### Patch Changes
diff --git a/libs/coin-modules/coin-evm/package.json b/libs/coin-modules/coin-evm/package.json
index a4475cd2cdcf..201eba35a096 100644
--- a/libs/coin-modules/coin-evm/package.json
+++ b/libs/coin-modules/coin-evm/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-evm",
- "version": "2.1.4",
+ "version": "2.2.0",
"description": "Ledger EVM Coin integration",
"keywords": [
"Ledger",
@@ -69,7 +69,7 @@
"@ledgerhq/live-network": "workspace:^",
"@ledgerhq/live-promise": "workspace:^",
"@ledgerhq/logs": "workspace:^",
- "axios": "0.26.1",
+ "axios": "1.7.3",
"bignumber.js": "^9.1.2",
"eip55": "^2.1.1",
"ethers": "5.7.2",
diff --git a/libs/coin-modules/coin-evm/src/__tests__/coin-tester/scenarios/polygon.ts b/libs/coin-modules/coin-evm/src/__tests__/coin-tester/scenarios/polygon.ts
index 301b3b40ea3d..96fc8a22146b 100644
--- a/libs/coin-modules/coin-evm/src/__tests__/coin-tester/scenarios/polygon.ts
+++ b/libs/coin-modules/coin-evm/src/__tests__/coin-tester/scenarios/polygon.ts
@@ -1,16 +1,17 @@
import Eth from "@ledgerhq/hw-app-eth";
import { BigNumber } from "bignumber.js";
import { ethers, providers } from "ethers";
+import { Account } from "@ledgerhq/types-live";
import { getCryptoCurrencyById } from "@ledgerhq/cryptoassets/currencies";
import { Scenario, ScenarioTransaction } from "@ledgerhq/coin-tester/main";
import { encodeTokenAccountId } from "@ledgerhq/coin-framework/account/index";
import { killSpeculos, spawnSpeculos } from "@ledgerhq/coin-tester/signers/speculos";
-import { Account } from "@ledgerhq/types-live";
import { resetIndexer, initMswHandlers, setBlock, indexBlocks } from "../indexer";
import { buildAccountBridge, buildCurrencyBridge } from "../../../bridge/js";
import { Transaction as EvmTransaction } from "../../../types";
import { getCoinConfig, setCoinConfig } from "../../../config";
import { makeAccount } from "../../fixtures/common.fixtures";
+import { defaultNanoApp } from "../scenarios.test";
import { killAnvil, spawnAnvil } from "../anvil";
import resolver from "../../../hw-getAddress";
import {
@@ -21,13 +22,12 @@ import {
impersonnateAccount,
polygon,
} from "../helpers";
-import { defaultNanoApp } from "../scenarios.test";
type PolygonScenarioTransaction = ScenarioTransaction;
const makeScenarioTransactions = ({ address }: { address: string }) => {
const send1MaticTransaction: PolygonScenarioTransaction = {
- name: "Send 1 Matic",
+ name: "Send 1 POL",
amount: new BigNumber(ethers.utils.parseEther("1").toString()),
recipient: ethers.constants.AddressZero,
expect: (previousAccount, currentAccount) => {
diff --git a/libs/coin-modules/coin-evm/src/__tests__/unit/api/node/ledger.unit.test.ts b/libs/coin-modules/coin-evm/src/__tests__/unit/api/node/ledger.unit.test.ts
index a54f473a4cd7..98064c26fee3 100644
--- a/libs/coin-modules/coin-evm/src/__tests__/unit/api/node/ledger.unit.test.ts
+++ b/libs/coin-modules/coin-evm/src/__tests__/unit/api/node/ledger.unit.test.ts
@@ -386,7 +386,7 @@ describe("EVM Family", () => {
}
});
- it("should return the medium value of the Ledger explorers gas tracker", async () => {
+ it("should return the fee data based on the transaction's feesStrategy", async () => {
jest.spyOn(LEDGER_GAS_TRACKER, "getGasOptions").mockImplementation(async () => ({
slow: {
maxFeePerGas: new BigNumber(1),
@@ -408,16 +408,64 @@ describe("EVM Family", () => {
},
}));
- const legacyFeeData = await LEDGER_API.getFeeData(currency, { type: 0 } as any);
- const eip1559FeeData = await LEDGER_API.getFeeData(currency, { type: 2 } as any);
-
- expect(legacyFeeData).toEqual({
+ const slowFeeData = await LEDGER_API.getFeeData(currency, {
+ type: 2,
+ feesStrategy: "slow",
+ } as any);
+ const mediumFeeData = await LEDGER_API.getFeeData(currency, {
+ type: 2,
+ feesStrategy: "medium",
+ } as any);
+ const fastFeeData = await LEDGER_API.getFeeData(currency, {
+ type: 2,
+ feesStrategy: "fast",
+ } as any);
+
+ expect(slowFeeData).toEqual({
+ maxFeePerGas: new BigNumber(1),
+ maxPriorityFeePerGas: new BigNumber(2),
+ gasPrice: new BigNumber(3),
+ nextBaseFee: new BigNumber(4),
+ });
+ expect(mediumFeeData).toEqual({
maxFeePerGas: new BigNumber(5),
maxPriorityFeePerGas: new BigNumber(6),
gasPrice: new BigNumber(7),
nextBaseFee: new BigNumber(8),
});
- expect(eip1559FeeData).toEqual({
+ expect(fastFeeData).toEqual({
+ maxFeePerGas: new BigNumber(9),
+ maxPriorityFeePerGas: new BigNumber(10),
+ gasPrice: new BigNumber(11),
+ nextBaseFee: new BigNumber(12),
+ });
+ });
+
+ it("should return medium fee data if feesStrategy is not provided", async () => {
+ jest.spyOn(LEDGER_GAS_TRACKER, "getGasOptions").mockImplementation(async () => ({
+ slow: {
+ maxFeePerGas: new BigNumber(1),
+ maxPriorityFeePerGas: new BigNumber(2),
+ gasPrice: new BigNumber(3),
+ nextBaseFee: new BigNumber(4),
+ },
+ medium: {
+ maxFeePerGas: new BigNumber(5),
+ maxPriorityFeePerGas: new BigNumber(6),
+ gasPrice: new BigNumber(7),
+ nextBaseFee: new BigNumber(8),
+ },
+ fast: {
+ maxFeePerGas: new BigNumber(9),
+ maxPriorityFeePerGas: new BigNumber(10),
+ gasPrice: new BigNumber(11),
+ nextBaseFee: new BigNumber(12),
+ },
+ }));
+
+ const feeData = await LEDGER_API.getFeeData(currency, { type: 2 } as any);
+
+ expect(feeData).toEqual({
maxFeePerGas: new BigNumber(5),
maxPriorityFeePerGas: new BigNumber(6),
gasPrice: new BigNumber(7),
diff --git a/libs/coin-modules/coin-evm/src/__tests__/unit/editTransaction/__snapshots__/getFormattedFeeFields.test.ts.snap b/libs/coin-modules/coin-evm/src/__tests__/unit/editTransaction/__snapshots__/getFormattedFeeFields.test.ts.snap
index 2b59c5c6e0ff..e55fd7135dca 100644
--- a/libs/coin-modules/coin-evm/src/__tests__/unit/editTransaction/__snapshots__/getFormattedFeeFields.test.ts.snap
+++ b/libs/coin-modules/coin-evm/src/__tests__/unit/editTransaction/__snapshots__/getFormattedFeeFields.test.ts.snap
@@ -398,7 +398,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale de-DE should correctly
exports[`getFormattedFeeFields with tx type 0 with locale de-DE should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -929,7 +929,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale en-US should correctly
exports[`getFormattedFeeFields with tx type 0 with locale en-US should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000105 MATIC",
+ "formattedFeeValue": "0.000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -1460,7 +1460,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale es-ES should correctly
exports[`getFormattedFeeFields with tx type 0 with locale es-ES should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -1991,7 +1991,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale fr-FR should correctly
exports[`getFormattedFeeFields with tx type 0 with locale fr-FR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -2522,7 +2522,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale ja-JP should correctly
exports[`getFormattedFeeFields with tx type 0 with locale ja-JP should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000105 MATIC",
+ "formattedFeeValue": "0.000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -3053,7 +3053,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale ko-KR should correctly
exports[`getFormattedFeeFields with tx type 0 with locale ko-KR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000105 MATIC",
+ "formattedFeeValue": "0.000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -3584,7 +3584,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale pt-BR should correctly
exports[`getFormattedFeeFields with tx type 0 with locale pt-BR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -4115,7 +4115,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale ru-RU should correctly
exports[`getFormattedFeeFields with tx type 0 with locale ru-RU should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -4646,7 +4646,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale tr-TR should correctly
exports[`getFormattedFeeFields with tx type 0 with locale tr-TR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000105 MATIC",
+ "formattedFeeValue": "0,000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -5177,7 +5177,7 @@ exports[`getFormattedFeeFields with tx type 0 with locale zh-CN should correctly
exports[`getFormattedFeeFields with tx type 0 with locale zh-CN should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000105 MATIC",
+ "formattedFeeValue": "0.000105 POL",
"formattedGasPrice": "5 Gwei",
"formattedMaxFeePerGas": "0 Gwei",
"formattedMaxPriorityFeePerGas": "0 Gwei",
@@ -5708,7 +5708,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale de-DE should correctly
exports[`getFormattedFeeFields with tx type 2 with locale de-DE should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -6239,7 +6239,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale en-US should correctly
exports[`getFormattedFeeFields with tx type 2 with locale en-US should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000042 MATIC",
+ "formattedFeeValue": "0.000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -6770,7 +6770,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale es-ES should correctly
exports[`getFormattedFeeFields with tx type 2 with locale es-ES should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -7301,7 +7301,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale fr-FR should correctly
exports[`getFormattedFeeFields with tx type 2 with locale fr-FR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -7832,7 +7832,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale ja-JP should correctly
exports[`getFormattedFeeFields with tx type 2 with locale ja-JP should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000042 MATIC",
+ "formattedFeeValue": "0.000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -8363,7 +8363,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale ko-KR should correctly
exports[`getFormattedFeeFields with tx type 2 with locale ko-KR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000042 MATIC",
+ "formattedFeeValue": "0.000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -8894,7 +8894,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale pt-BR should correctly
exports[`getFormattedFeeFields with tx type 2 with locale pt-BR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -9425,7 +9425,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale ru-RU should correctly
exports[`getFormattedFeeFields with tx type 2 with locale ru-RU should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -9956,7 +9956,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale tr-TR should correctly
exports[`getFormattedFeeFields with tx type 2 with locale tr-TR should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0,000042 MATIC",
+ "formattedFeeValue": "0,000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
@@ -10487,7 +10487,7 @@ exports[`getFormattedFeeFields with tx type 2 with locale zh-CN should correctly
exports[`getFormattedFeeFields with tx type 2 with locale zh-CN should correctly format fee fields for Polygon unit 1`] = `
{
- "formattedFeeValue": "0.000042 MATIC",
+ "formattedFeeValue": "0.000042 POL",
"formattedGasPrice": "0 Gwei",
"formattedMaxFeePerGas": "2 Gwei",
"formattedMaxPriorityFeePerGas": "1 Gwei",
diff --git a/libs/coin-modules/coin-evm/src/__tests__/unit/getTransactionStatus.unit.test.ts b/libs/coin-modules/coin-evm/src/__tests__/unit/getTransactionStatus.unit.test.ts
index 01923b7d6d7b..e403a6a5b654 100644
--- a/libs/coin-modules/coin-evm/src/__tests__/unit/getTransactionStatus.unit.test.ts
+++ b/libs/coin-modules/coin-evm/src/__tests__/unit/getTransactionStatus.unit.test.ts
@@ -8,7 +8,6 @@ import {
InvalidAddress,
MaxFeeTooLow,
NotEnoughBalance,
- NotEnoughBalanceInParentAccount,
NotEnoughGas,
PriorityFeeHigherThanMaxFee,
PriorityFeeTooHigh,
@@ -242,18 +241,15 @@ describe("EVM Family", () => {
);
});
- it("should detected parent account not having enough fund for a token transaction and have an error", async () => {
+ it("should detect token account not having enough balance for a tx and have an error", async () => {
const res = await getTransactionStatus(
- {
- ...account,
- balance: new BigNumber(0),
- },
+ { ...account, subAccounts: [{ ...tokenAccount, balance: new BigNumber(0) }] },
erc20Transaction,
);
expect(res.errors).toEqual(
expect.objectContaining({
- amount: new NotEnoughBalanceInParentAccount(),
+ amount: new NotEnoughBalance(),
}),
);
});
diff --git a/libs/coin-modules/coin-evm/src/__tests__/unit/prepareTransaction.unit.test.ts b/libs/coin-modules/coin-evm/src/__tests__/unit/prepareTransaction.unit.test.ts
index 1440e8952e93..1cb1d55abd49 100644
--- a/libs/coin-modules/coin-evm/src/__tests__/unit/prepareTransaction.unit.test.ts
+++ b/libs/coin-modules/coin-evm/src/__tests__/unit/prepareTransaction.unit.test.ts
@@ -179,6 +179,33 @@ describe("EVM Family", () => {
});
});
+ it("should return a legacy coin transaction when passing a gasPrice and custom feesStrategy", async () => {
+ jest.spyOn(nodeApi, "getFeeData").mockImplementationOnce(async () => ({
+ gasPrice: new BigNumber(1),
+ maxFeePerGas: null,
+ maxPriorityFeePerGas: null,
+ nextBaseFee: null,
+ }));
+
+ // @ts-expect-error - mixed type0/2
+ const tx = await prepareTransaction(account, {
+ ...transaction,
+ feesStrategy: "custom",
+ gasPrice: new BigNumber(1),
+ maxFeePerGas: new BigNumber(0),
+ maxPriorityFeePerGas: new BigNumber(0),
+ });
+
+ expect(tx).toEqual({
+ ...transaction,
+ gasPrice: new BigNumber(1),
+ feesStrategy: "custom",
+ maxFeePerGas: undefined,
+ maxPriorityFeePerGas: undefined,
+ type: 0,
+ });
+ });
+
it("should create a coin transaction using all amount in the account", async () => {
const accountWithBalance = {
...account,
@@ -555,13 +582,13 @@ describe("EVM Family", () => {
});
describe("When custom feesStrategy provided", () => {
- it("should use transaction provided data for fees", async () => {
+ it("should also call getFeeData to determine the gas price and type", async () => {
const tx = await prepareTransaction(account, {
...transaction,
feesStrategy: "custom",
});
- expect(nodeApi.getFeeData).toBeCalledTimes(0);
+ expect(nodeApi.getFeeData).toBeCalledTimes(1);
expect(tx).toEqual({
...transaction,
diff --git a/libs/coin-modules/coin-evm/src/api/node/ledger.ts b/libs/coin-modules/coin-evm/src/api/node/ledger.ts
index 9d3065f33063..835b6fda0f32 100644
--- a/libs/coin-modules/coin-evm/src/api/node/ledger.ts
+++ b/libs/coin-modules/coin-evm/src/api/node/ledger.ts
@@ -229,7 +229,7 @@ export const getFeeData: NodeApi["getFeeData"] = async (currency, transaction) =
throw new LedgerNodeUsedIncorrectly();
}
- const { medium } = await getGasOptions({
+ const options = await getGasOptions({
currency: {
...currency,
ethereumLikeInfo: {
@@ -249,7 +249,7 @@ export const getFeeData: NodeApi["getFeeData"] = async (currency, transaction) =
},
});
- return medium;
+ return options?.[transaction.feesStrategy as keyof typeof options] ?? options.medium;
};
/**
diff --git a/libs/coin-modules/coin-evm/src/getTransactionStatus.ts b/libs/coin-modules/coin-evm/src/getTransactionStatus.ts
index 8efe054c5229..56dba1a4aea5 100644
--- a/libs/coin-modules/coin-evm/src/getTransactionStatus.ts
+++ b/libs/coin-modules/coin-evm/src/getTransactionStatus.ts
@@ -7,7 +7,6 @@ import {
InvalidAddress,
MaxFeeTooLow,
NotEnoughBalance,
- NotEnoughBalanceInParentAccount,
NotEnoughGas,
PriorityFeeHigherThanMaxFee,
PriorityFeeTooHigh,
@@ -118,9 +117,7 @@ const validateAmount = (
errors.amount = new AmountRequired(); // "Amount required"
} else if (totalSpent.isGreaterThan(account.balance)) {
// if not enough to make the transaction
- errors.amount = isTokenTransaction
- ? new NotEnoughBalanceInParentAccount() // Insufficient balance in the parent account
- : new NotEnoughBalance(); // "Sorry, insufficient funds"
+ errors.amount = new NotEnoughBalance(); // "Sorry, insufficient funds"
}
return [errors, warnings];
};
diff --git a/libs/coin-modules/coin-evm/src/prepareTransaction.ts b/libs/coin-modules/coin-evm/src/prepareTransaction.ts
index 0a7ae7076d70..085757b3770f 100644
--- a/libs/coin-modules/coin-evm/src/prepareTransaction.ts
+++ b/libs/coin-modules/coin-evm/src/prepareTransaction.ts
@@ -210,10 +210,16 @@ export const prepareTransaction = async (
// Get the current network status fees
const feeData: FeeData = await (async (): Promise => {
if (transaction.feesStrategy === "custom") {
+ const gasOption = await nodeApi.getFeeData(currency, transaction);
+
return {
- gasPrice: transaction.gasPrice ?? null,
- maxFeePerGas: transaction.maxFeePerGas ?? null,
- maxPriorityFeePerGas: transaction.maxPriorityFeePerGas ?? null,
+ gasPrice: gasOption.gasPrice && transaction.gasPrice ? transaction.gasPrice : null,
+ maxFeePerGas:
+ gasOption.maxFeePerGas && transaction.maxFeePerGas ? transaction.maxFeePerGas : null,
+ maxPriorityFeePerGas:
+ gasOption.maxPriorityFeePerGas && transaction.maxPriorityFeePerGas
+ ? transaction.maxPriorityFeePerGas
+ : null,
nextBaseFee: transaction.gasOptions?.medium?.nextBaseFee ?? null,
};
}
diff --git a/libs/coin-modules/coin-icon/CHANGELOG.md b/libs/coin-modules/coin-icon/CHANGELOG.md
index 33e67d0a8c54..b17f13e26e1d 100644
--- a/libs/coin-modules/coin-icon/CHANGELOG.md
+++ b/libs/coin-modules/coin-icon/CHANGELOG.md
@@ -1,5 +1,37 @@
# @ledgerhq/coin-algorand
+## 0.4.2
+
+### Patch Changes
+
+- [#7672](https://github.com/LedgerHQ/ledger-live/pull/7672) [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add support for jettons
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.4.2-next.0
+
+### Patch Changes
+
+- [#7672](https://github.com/LedgerHQ/ledger-live/pull/7672) [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - Add support for jettons
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.4.1
### Patch Changes
diff --git a/libs/coin-modules/coin-icon/package.json b/libs/coin-modules/coin-icon/package.json
index affd9ef51af1..c2f685efeba1 100644
--- a/libs/coin-modules/coin-icon/package.json
+++ b/libs/coin-modules/coin-icon/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-icon",
- "version": "0.4.1",
+ "version": "0.4.2",
"description": "Ledger Icon Coin integration",
"keywords": [
"Ledger",
diff --git a/libs/coin-modules/coin-near/CHANGELOG.md b/libs/coin-modules/coin-near/CHANGELOG.md
index d1e3b7c09a09..10888f30a3d2 100644
--- a/libs/coin-modules/coin-near/CHANGELOG.md
+++ b/libs/coin-modules/coin-near/CHANGELOG.md
@@ -1,5 +1,31 @@
# @ledgerhq/coin-near
+## 0.5.5
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 0.5.5-next.0
+
+### Patch Changes
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 0.5.4
### Patch Changes
diff --git a/libs/coin-modules/coin-near/package.json b/libs/coin-modules/coin-near/package.json
index be8ce09e1df2..5d8cd577d9b5 100644
--- a/libs/coin-modules/coin-near/package.json
+++ b/libs/coin-modules/coin-near/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-near",
- "version": "0.5.4",
+ "version": "0.5.5",
"description": "Near Coin integration",
"keywords": [
"Ledger",
diff --git a/libs/coin-modules/coin-polkadot/CHANGELOG.md b/libs/coin-modules/coin-polkadot/CHANGELOG.md
index 3c2054355f11..35967268330a 100644
--- a/libs/coin-modules/coin-polkadot/CHANGELOG.md
+++ b/libs/coin-modules/coin-polkadot/CHANGELOG.md
@@ -1,5 +1,45 @@
# @ledgerhq/coin-polkadot
+## 1.2.1
+
+### Patch Changes
+
+- [#7470](https://github.com/LedgerHQ/ledger-live/pull/7470) [`93128e3`](https://github.com/LedgerHQ/ledger-live/commit/93128e367e6bff621309334f163198b9c07fb92e) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - get rid of sidecar fork api and fix validator list for polkadot
+
+- [#7695](https://github.com/LedgerHQ/ledger-live/pull/7695) [`bb1ca23`](https://github.com/LedgerHQ/ledger-live/commit/bb1ca23865c787ef18b7623162487e3045c22ded) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Rename network model types
+
+- [#7268](https://github.com/LedgerHQ/ledger-live/pull/7268) [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Prepare CoinModule Stellar for Alpaca
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0
+ - @ledgerhq/cryptoassets@13.4.0
+ - @ledgerhq/live-network@2.0.0
+ - @ledgerhq/coin-framework@0.18.0
+ - @ledgerhq/types-live@6.51.0
+ - @ledgerhq/live-env@2.3.0
+ - @ledgerhq/types-cryptoassets@7.15.1
+ - @ledgerhq/devices@8.4.3
+
+## 1.2.1-next.0
+
+### Patch Changes
+
+- [#7470](https://github.com/LedgerHQ/ledger-live/pull/7470) [`93128e3`](https://github.com/LedgerHQ/ledger-live/commit/93128e367e6bff621309334f163198b9c07fb92e) Thanks [@hzheng-ledger](https://github.com/hzheng-ledger)! - get rid of sidecar fork api and fix validator list for polkadot
+
+- [#7695](https://github.com/LedgerHQ/ledger-live/pull/7695) [`bb1ca23`](https://github.com/LedgerHQ/ledger-live/commit/bb1ca23865c787ef18b7623162487e3045c22ded) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Rename network model types
+
+- [#7268](https://github.com/LedgerHQ/ledger-live/pull/7268) [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae) Thanks [@sprohaszka-ledger](https://github.com/sprohaszka-ledger)! - Prepare CoinModule Stellar for Alpaca
+
+- Updated dependencies [[`5c738cb`](https://github.com/LedgerHQ/ledger-live/commit/5c738cbd35ce5d0ca39ad3b86a61cc6234d1bdf7), [`9c55e81`](https://github.com/LedgerHQ/ledger-live/commit/9c55e81c84d3372f2a7fd36248f970376aec905a), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`187293c`](https://github.com/LedgerHQ/ledger-live/commit/187293c6cf6093f15f07d5effc1ded0843a9e6ab), [`cc291f5`](https://github.com/LedgerHQ/ledger-live/commit/cc291f5466d80a2b7e9394338ab588ecd3db4623), [`fb9466a`](https://github.com/LedgerHQ/ledger-live/commit/fb9466a4d7827fd4759c726ad3ae0b43dddcacd3), [`5758950`](https://github.com/LedgerHQ/ledger-live/commit/5758950841fbf8018dd848e745017484aec67333), [`0c80144`](https://github.com/LedgerHQ/ledger-live/commit/0c80144b8c16fc3729baa6503875d21af87b2752), [`4799d5d`](https://github.com/LedgerHQ/ledger-live/commit/4799d5de3fb1dcef2b01de31fe29b59e76922576), [`ef82161`](https://github.com/LedgerHQ/ledger-live/commit/ef82161688fc49bf32cbc88f1837b15490e5d2b4), [`d13e7b9`](https://github.com/LedgerHQ/ledger-live/commit/d13e7b9f55d92098cacc9384fd7fab24033c040f), [`a3fd728`](https://github.com/LedgerHQ/ledger-live/commit/a3fd72861f2a7df676bd793062b3816fdb9d1f57), [`a0bb74b`](https://github.com/LedgerHQ/ledger-live/commit/a0bb74b8f3704ab9d5567c9d14c16cab9e0872f7), [`eb9a36f`](https://github.com/LedgerHQ/ledger-live/commit/eb9a36f6ee8487c9ffbb841c3e6c0ca84f68bb0a), [`6815f6f`](https://github.com/LedgerHQ/ledger-live/commit/6815f6fccb9bca627a2e51ab954dc3f9b8f7c710), [`9c2f1b3`](https://github.com/LedgerHQ/ledger-live/commit/9c2f1b3b6e11a37a6b5ecf02d1e1ae7f0258e3ae), [`9a650da`](https://github.com/LedgerHQ/ledger-live/commit/9a650da9a147d6881f7082278d2bf764c37e1451)]:
+ - @ledgerhq/errors@6.19.0-next.0
+ - @ledgerhq/cryptoassets@13.4.0-next.0
+ - @ledgerhq/live-network@2.0.0-next.0
+ - @ledgerhq/coin-framework@0.18.0-next.0
+ - @ledgerhq/types-live@6.51.0-next.0
+ - @ledgerhq/live-env@2.3.0-next.0
+ - @ledgerhq/types-cryptoassets@7.15.1-next.0
+ - @ledgerhq/devices@8.4.3-next.0
+
## 1.2.0
### Minor Changes
diff --git a/libs/coin-modules/coin-polkadot/package.json b/libs/coin-modules/coin-polkadot/package.json
index ad011ce99ef1..2abf5570021f 100644
--- a/libs/coin-modules/coin-polkadot/package.json
+++ b/libs/coin-modules/coin-polkadot/package.json
@@ -1,6 +1,6 @@
{
"name": "@ledgerhq/coin-polkadot",
- "version": "1.2.0",
+ "version": "1.2.1",
"description": "Ledger Polkadot Coin integration",
"keywords": [
"Ledger",
diff --git a/libs/coin-modules/coin-polkadot/src/api/index.integ.test.ts b/libs/coin-modules/coin-polkadot/src/api/index.integ.test.ts
index 0cb00ca9967e..d9ec07f9eb02 100644
--- a/libs/coin-modules/coin-polkadot/src/api/index.integ.test.ts
+++ b/libs/coin-modules/coin-polkadot/src/api/index.integ.test.ts
@@ -52,7 +52,7 @@ describe("Polkadot Api", () => {
operation.senders.includes(address) || operation.recipients.includes(address);
expect(isSenderOrReceipt).toBeTruthy();
});
- });
+ }, 20000);
});
describe("lastBlock", () => {
@@ -81,6 +81,7 @@ describe("Polkadot Api", () => {
it("returns a raw transaction", async () => {
// When
const result = await module.craftTransaction(address, {
+ mode: "send",
recipient: "16YreVmGhM8mNMqnsvK7rn7b1e4SKYsTfFUn4UfCZ65BgDjh",
amount: BigInt(10),
fee: BigInt(1),
diff --git a/libs/coin-modules/coin-polkadot/src/api/index.ts b/libs/coin-modules/coin-polkadot/src/api/index.ts
index 22fed372c431..5a9ea2a87073 100644
--- a/libs/coin-modules/coin-polkadot/src/api/index.ts
+++ b/libs/coin-modules/coin-polkadot/src/api/index.ts
@@ -30,8 +30,11 @@ export function createApi(config: PolkadotConfig): Api {
async function craft(
address: string,
transaction: {
+ mode: string;
recipient: string;
amount: bigint;
+ fee: bigint;
+ supplement?: unknown;
},
): Promise {
const extrinsicArg = defaultExtrinsicArg(transaction.amount, transaction.recipient);
diff --git a/libs/coin-modules/coin-polkadot/src/network/common.ts b/libs/coin-modules/coin-polkadot/src/network/common.ts
index be647c262a03..2bc89fc06e8d 100644
--- a/libs/coin-modules/coin-polkadot/src/network/common.ts
+++ b/libs/coin-modules/coin-polkadot/src/network/common.ts
@@ -1,7 +1,7 @@
import { expandMetadata, Metadata, TypeRegistry } from "@polkadot/types";
import { getSpecTypes } from "@polkadot/types-known";
import { Extrinsics } from "@polkadot/types/metadata/decorate/types";
-import { SidecarRuntimeSpec, SidecarTransactionMaterial } from "./sidecar.types";
+import { SidecarRuntimeSpec, SidecarTransactionMaterial } from "./types";
export const createRegistryAndExtrinsics = (
material: SidecarTransactionMaterial,
diff --git a/libs/coin-modules/coin-polkadot/src/network/node/identities.ts b/libs/coin-modules/coin-polkadot/src/network/node/identities.ts
deleted file mode 100644
index 84720fb80637..000000000000
--- a/libs/coin-modules/coin-polkadot/src/network/node/identities.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import { AccountId, Registration } from "@polkadot/types/interfaces";
-import { ITuple } from "@polkadot/types/types";
-import { Bytes, Data, Option } from "@polkadot/types";
-import { u8aToString } from "@polkadot/util";
-import { ApiPromise } from "@polkadot/api";
-import { IIdentity } from "../sidecar.types";
-import getApiPromise from "./apiPromise";
-
-export async function multiIdentities(addresses: AccountId[] | string[]): Promise {
- const api = await getApiPromise();
-
- const [identities, superOfOpts] = await Promise.all([
- api.query.identity.identityOf.multi(addresses),
- api.query.identity.superOf.multi