diff --git a/.github/workflows/build-mobile-reusable.yml b/.github/workflows/build-mobile-reusable.yml index 92363200aa1c..347fc148042d 100644 --- a/.github/workflows/build-mobile-reusable.yml +++ b/.github/workflows/build-mobile-reusable.yml @@ -106,8 +106,13 @@ jobs: skip-pod-cache: "false" skip-turbo-cache: "false" turbo-server-token: ${{ secrets.TURBOREPO_SERVER_TOKEN }} - - name: install dependencies - run: pnpm i --filter="live-mobile..." --filter="ledger-live" --no-frozen-lockfile --unsafe-perm + - uses: nick-fields/retry@v3 + name: install dependencies + with: + max_attempts: 2 + timeout_minutes: 15 + command: pnpm i --filter="live-mobile..." --filter="ledger-live" --no-frozen-lockfile --unsafe-perm + new_command_on_retry: rm -rf ~/.cocoapods/ && pnpm clean && pnpm i --filter="live-mobile..." --filter="ledger-live" --no-frozen-lockfile --unsafe-perm - name: bundle ios and android js run: | pnpm build:llm:deps --api="http://127.0.0.1:${{ steps.caches.outputs.port }}" --token="${{ secrets.TURBOREPO_SERVER_TOKEN }}" --team="foo" diff --git a/.github/workflows/release-final-nightly.yml b/.github/workflows/release-final-nightly.yml index 3998336d3de9..1b08a670650c 100644 --- a/.github/workflows/release-final-nightly.yml +++ b/.github/workflows/release-final-nightly.yml @@ -57,7 +57,7 @@ jobs: git add . git commit -m "chore(nightly): :rocket: nightly release" - name: publish nightly - run: pnpm changeset publish + run: pnpm changeset publish --no-git-tag env: NODE_AUTH_TOKEN: ${{ secrets.NPMJS_TOKEN }} - uses: LedgerHQ/ledger-live/tools/actions/get-package-infos@develop @@ -68,18 +68,10 @@ jobs: id: post-mobile-version with: path: ${{ github.workspace }}/apps/ledger-live-mobile - - name: tag desktop - if: ${{ steps.desktop-version.outputs.version != steps.post-desktop-version.outputs.version }} - run: | - git tag @ledgerhq/live-desktop@${{ steps.post-desktop-version.outputs.version }} - - name: tag mobile - if: ${{ steps.mobile-version.outputs.version != steps.post-mobile-version.outputs.version }} - run: | - git tag live-mobile@${{ steps.post-mobile-version.outputs.version }} - name: push changes if: ${{ !cancelled() }} run: | - git push origin nightly --follow-tags + git push origin nightly - uses: actions/github-script@v7 name: trigger nightly build of desktop if: ${{ steps.desktop-version.outputs.version != steps.post-desktop-version.outputs.version }} diff --git a/.github/workflows/release-prerelease.yml b/.github/workflows/release-prerelease.yml index f135318b9c89..c4a522b3ea57 100644 --- a/.github/workflows/release-prerelease.yml +++ b/.github/workflows/release-prerelease.yml @@ -86,27 +86,19 @@ jobs: git commit -m "chore(prerelease): :rocket: ${{ inputs.ref }} prerelease [LLD(${{ steps.post-desktop-version.outputs.version }}), LLM(${{ steps.post-mobile-version.outputs.version }})]" || echo "" - name: publish prerelease - run: pnpm changeset publish + run: pnpm changeset publish --no-git-tag env: NODE_AUTH_TOKEN: ${{ secrets.NPMJS_TOKEN }} - - name: tag desktop - if: ${{ steps.desktop-version.outputs.version != steps.post-desktop-version.outputs.version }} - run: | - git tag @ledgerhq/live-desktop@${{ steps.post-desktop-version.outputs.version }} - - name: tag mobile - if: ${{ steps.mobile-version.outputs.version != steps.post-mobile-version.outputs.version }} - run: | - git tag live-mobile@${{ steps.post-mobile-version.outputs.version }} - name: push changes (push event) if: ${{ github.event_name == 'push' }} run: | git pull --rebase - git push origin ${{ github.ref_name }} --follow-tags + git push origin ${{ github.ref_name }} - name: push changes (other events) if: ${{ github.event_name == 'workflow_dispatch' }} run: | git pull --rebase - git push origin ${{ inputs.ref }} --follow-tags + git push origin ${{ inputs.ref }} - uses: actions/github-script@v7 name: trigger prerelease build for desktop if: ${{ steps.desktop-version.outputs.version != steps.post-desktop-version.outputs.version }} diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md index 191fd35f01f2..974f13d96a27 100644 --- a/apps/cli/CHANGELOG.md +++ b/apps/cli/CHANGELOG.md @@ -1,5 +1,46 @@ # @ledgerhq/live-cli +## 24.7.1 + +### Patch Changes + +- Updated dependencies [[`642c714`](https://github.com/LedgerHQ/ledger-live/commit/642c714d52eaaccb1b8ac3a2ee0391b641d19303), [`ced792c`](https://github.com/LedgerHQ/ledger-live/commit/ced792c37b42135f2b7596228c14ccd0783a803f), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba), [`0a16ae4`](https://github.com/LedgerHQ/ledger-live/commit/0a16ae4cb58ad9f2e67c7f3494b0dc52cb7423a1), [`6f0d39f`](https://github.com/LedgerHQ/ledger-live/commit/6f0d39f46ef5d3e24439421aa68dfe7aadcd1dbc), [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`a47e68b`](https://github.com/LedgerHQ/ledger-live/commit/a47e68b568a3b888a241c30345b4935557404215), [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7), [`3652e83`](https://github.com/LedgerHQ/ledger-live/commit/3652e83e02876856f1370cccab47f4272b71a7d3), [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7), [`3824e06`](https://github.com/LedgerHQ/ledger-live/commit/3824e06ba2c94bc0697d2a40d865efe766d1f102), [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4)]: + - @ledgerhq/live-common@34.11.0 + - @ledgerhq/live-env@2.4.0 + - @ledgerhq/ledger-key-ring-protocol@0.5.0 + - @ledgerhq/hw-ledger-key-ring-protocol@0.2.0 + - @ledgerhq/live-wallet@0.7.0 + - @ledgerhq/coin-bitcoin@0.8.3 + - @ledgerhq/coin-framework@0.18.3 + - @ledgerhq/device-core@0.4.2 + - @ledgerhq/live-countervalues@0.2.8 + - @ledgerhq/cryptoassets@13.6.1 + - @ledgerhq/live-network@2.0.2 + +## 24.7.1-next.1 + +### Patch Changes + +- Updated dependencies [[`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba)]: + - @ledgerhq/live-common@34.11.0-next.1 + +## 24.7.1-next.0 + +### Patch Changes + +- Updated dependencies [[`642c714`](https://github.com/LedgerHQ/ledger-live/commit/642c714d52eaaccb1b8ac3a2ee0391b641d19303), [`ced792c`](https://github.com/LedgerHQ/ledger-live/commit/ced792c37b42135f2b7596228c14ccd0783a803f), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`0a16ae4`](https://github.com/LedgerHQ/ledger-live/commit/0a16ae4cb58ad9f2e67c7f3494b0dc52cb7423a1), [`6f0d39f`](https://github.com/LedgerHQ/ledger-live/commit/6f0d39f46ef5d3e24439421aa68dfe7aadcd1dbc), [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`87b706c`](https://github.com/LedgerHQ/ledger-live/commit/87b706c8a807f14c72c7d47206e9ee767f50a04c), [`a47e68b`](https://github.com/LedgerHQ/ledger-live/commit/a47e68b568a3b888a241c30345b4935557404215), [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7), [`3652e83`](https://github.com/LedgerHQ/ledger-live/commit/3652e83e02876856f1370cccab47f4272b71a7d3), [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7), [`3824e06`](https://github.com/LedgerHQ/ledger-live/commit/3824e06ba2c94bc0697d2a40d865efe766d1f102), [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4)]: + - @ledgerhq/live-common@34.11.0-next.0 + - @ledgerhq/live-env@2.4.0-next.0 + - @ledgerhq/ledger-key-ring-protocol@0.5.0-next.0 + - @ledgerhq/hw-ledger-key-ring-protocol@0.2.0-next.0 + - @ledgerhq/live-wallet@0.7.0-next.0 + - @ledgerhq/coin-bitcoin@0.8.3-next.0 + - @ledgerhq/coin-framework@0.18.3-next.0 + - @ledgerhq/device-core@0.4.2-next.0 + - @ledgerhq/live-countervalues@0.2.8-next.0 + - @ledgerhq/cryptoassets@13.6.1-next.0 + - @ledgerhq/live-network@2.0.2-next.0 + ## 24.7.0 ### Minor Changes diff --git a/apps/cli/README.md b/apps/cli/README.md index aa6ce8532356..5fa1a7fa2058 100644 --- a/apps/cli/README.md +++ b/apps/cli/README.md @@ -376,6 +376,40 @@ Usage: ledger-live i18n # Test e2e functionality for device localization s Usage: ledger-live listApps # list all installed apps on the device -d, --device : provide a specific HID path of a device +Usage: ledger-live ledgerKeyRingProtocol # Ledger Key Ring Protocol command + -d, --device : provide a specific HID path of a device + --initMemberCredentials : Init member credentials for Ledger Key Ring Protocol + --getKeyRingTree : Get or create a Ledger Key Ring Protocol Tree + --encryptUserData : Encrypt user data with the current private key secured by the Ledger Key Ring Protocol + --decryptUserData : Encrypt user data with the current private key secured by the Ledger Key Ring Protocol + --getMembers : Get members of the Ledger Key Ring Protocol Tree + --restoreKeyRingTree : Restore a Ledger Key Ring Protocol Tree + --destroyKeyRingTree : Destroy a Ledger Key Ring Protocol Tree + --pubKey : pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result + --privateKey : privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result + --rootId : The immutable id of the Tree root retrieved from getKeyRingTree result + --walletSyncEncryptionKey : The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result + --applicationPath : privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result + --message : message to be encrypted/decrypted + --applicationId : application identifier + --name : name of the instance + --apiBaseUrl : api base url for Ledger Key Ring Protocol + +Usage: ledger-live ledgerSync # Ledger Sync command + --push : Init member credentials for Ledger Key Ring Protocol + --pull : Get or create a Ledger Key Ring Protocol Tree + --pubKey : pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result + --privateKey : privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result + --rootId : The immutable id of the Tree root retrieved from getKeyRingTree result + --walletSyncEncryptionKey : The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result + --applicationPath : privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result + --data : data to be pushed to Ledger Sync + --version : version of the data + --applicationId : application identifier + --name : name of the instance + --apiBaseUrl : api base url for Ledger Key Ring Protocol + --cloudSyncApiBaseUrl : api base url for Cloud Sync + Usage: ledger-live liveData # utility for Ledger Live app.json file -d, --device : provide a specific HID path of a device --xpub : use an xpub (alternatively to --device) [DEPRECATED: prefer use of id] diff --git a/apps/cli/package.json b/apps/cli/package.json index 964d470c5470..ad1a2ed294fb 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@ledgerhq/live-cli", - "version": "24.7.0", + "version": "24.7.1", "description": "ledger-live CLI version", "repository": { "type": "git", @@ -33,7 +33,9 @@ "@ledgerhq/device-core": "workspace:^", "@ledgerhq/devices": "workspace:^", "@ledgerhq/errors": "workspace:^", + "@ledgerhq/ledger-key-ring-protocol": "workspace:^", "@ledgerhq/hw-app-btc": "workspace:^", + "@ledgerhq/hw-ledger-key-ring-protocol": "workspace:^", "@ledgerhq/hw-transport": "workspace:^", "@ledgerhq/hw-transport-http": "workspace:^", "@ledgerhq/hw-transport-mocker": "workspace:^", diff --git a/apps/cli/src/commands-index.ts b/apps/cli/src/commands-index.ts index fb05590763c9..2bcd5aeb3627 100644 --- a/apps/cli/src/commands-index.ts +++ b/apps/cli/src/commands-index.ts @@ -54,6 +54,8 @@ import balanceHistory from "./commands/live/balanceHistory"; import countervalues from "./commands/live/countervalues"; import envs from "./commands/live/envs"; import exportAccounts from "./commands/live/exportAccounts"; +import ledgerKeyRingProtocol from "./commands/live/ledgerKeyRingProtocol"; +import ledgerSync from "./commands/live/ledgerSync"; import liveData from "./commands/live/liveData"; import portfolio from "./commands/live/portfolio"; import synchronousOnboarding from "./commands/live/synchronousOnboarding"; @@ -118,6 +120,8 @@ export default { countervalues, envs, exportAccounts, + ledgerKeyRingProtocol, + ledgerSync, liveData, portfolio, synchronousOnboarding, diff --git a/apps/cli/src/commands/live/ledgerKeyRingProtocol.ts b/apps/cli/src/commands/live/ledgerKeyRingProtocol.ts new file mode 100644 index 000000000000..1698eebeb009 --- /dev/null +++ b/apps/cli/src/commands/live/ledgerKeyRingProtocol.ts @@ -0,0 +1,195 @@ +import { getSdk } from "@ledgerhq/ledger-key-ring-protocol/index"; +import { crypto } from "@ledgerhq/hw-ledger-key-ring-protocol"; +import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess"; +import { getEnv } from "@ledgerhq/live-env"; +import { deviceOpt } from "../../scan"; + +export default { + description: "Ledger Key Ring Protocol command", + args: [ + deviceOpt, + { + name: "initMemberCredentials", + type: Boolean, + desc: "Init member credentials for Ledger Key Ring Protocol", + }, + { + name: "getKeyRingTree", + type: Boolean, + desc: "Get or create a Ledger Key Ring Protocol Tree", + }, + { + name: "encryptUserData", + type: Boolean, + desc: "Encrypt user data with the current private key secured by the Ledger Key Ring Protocol", + }, + { + name: "decryptUserData", + type: Boolean, + desc: "Encrypt user data with the current private key secured by the Ledger Key Ring Protocol", + }, + { + name: "getMembers", + type: Boolean, + desc: "Get members of the Ledger Key Ring Protocol Tree", + }, + { + name: "restoreKeyRingTree", + type: Boolean, + desc: "Restore a Ledger Key Ring Protocol Tree", + }, + { + name: "destroyKeyRingTree", + type: Boolean, + desc: "Destroy a Ledger Key Ring Protocol Tree", + }, + { + name: "pubKey", + type: String, + desc: "pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result", + }, + { + name: "privateKey", + type: String, + desc: "privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result", + }, + { + name: "rootId", + type: String, + desc: "The immutable id of the Tree root retrieved from getKeyRingTree result", + }, + { + name: "walletSyncEncryptionKey", + type: String, + desc: "The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result", + }, + { + name: "applicationPath", + type: String, + desc: "privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result", + }, + { + name: "message", + type: String, + desc: "message to be encrypted/decrypted", + }, + { + name: "applicationId", + type: Number, + default: 16, + desc: "application identifier", + }, + { + name: "name", + type: String, + default: "CLI", + desc: "name of the instance", + }, + { + name: "apiBaseUrl", + type: String, + default: getEnv("TRUSTCHAIN_API_STAGING"), + desc: "api base url for Ledger Key Ring Protocol", + }, + ], + job: ({ + device, + initMemberCredentials, + getKeyRingTree, + encryptUserData, + decryptUserData, + getMembers, + restoreKeyRingTree, + destroyKeyRingTree, + pubKey, + privateKey, + rootId, + walletSyncEncryptionKey, + applicationPath, + message, + applicationId = 16, + name = "CLI", + apiBaseUrl = getEnv("TRUSTCHAIN_API_STAGING"), + }: Partial<{ + device: string; + initMemberCredentials: boolean; + getKeyRingTree: boolean; + getMembers: boolean; + encryptUserData: boolean; + decryptUserData: boolean; + restoreKeyRingTree: boolean; + destroyKeyRingTree: boolean; + pubKey: string; + privateKey: string; + rootId: string; + walletSyncEncryptionKey: string; + applicationPath: string; + message: string; + applicationId: number; + name: string; + apiBaseUrl: string; + }>) => { + if (!applicationId) return "applicationId is required"; + if (!name) return "name is required"; + if (!apiBaseUrl) return "apiBaseUrl is required"; + + const context = { + applicationId, + name, + apiBaseUrl, + }; + const sdk = getSdk(false, context, withDevice); + + if (initMemberCredentials) { + return sdk.initMemberCredentials(); + } + + if (getKeyRingTree) { + if (!pubKey || !privateKey) return "pubKey and privateKey are required"; + return sdk + .getOrCreateTrustchain(device || "", { pubkey: pubKey, privatekey: privateKey }) + .then(result => result.trustchain); + } + + if (getMembers || restoreKeyRingTree || destroyKeyRingTree) { + if (!pubKey || !privateKey) return "pubKey and privateKey are required"; + if (!rootId) return "pubKey and privateKey are required"; + if (!walletSyncEncryptionKey) return "walletSyncEncryptionKey is required"; + if (!applicationPath) return "applicationPath is required"; + + const sdkMethod = getMembers + ? "getMembers" + : restoreKeyRingTree + ? "restoreTrustchain" + : "destroyTrustchain"; + return sdk[sdkMethod]( + { rootId, walletSyncEncryptionKey, applicationPath }, + { pubkey: pubKey, privatekey: privateKey }, + ); + } + + if (encryptUserData || decryptUserData) { + if (!rootId) return "rootId is required"; + if (!walletSyncEncryptionKey) return "walletSyncEncryptionKey is required"; + if (!applicationPath) return "applicationPath is required"; + if (!message) return "message is required"; + + if (encryptUserData) { + return sdk + .encryptUserData( + { rootId, walletSyncEncryptionKey, applicationPath }, + new TextEncoder().encode(message), + ) + .then(array => Buffer.from(array).toString("hex")); + } + return sdk + .decryptUserData( + { rootId, walletSyncEncryptionKey, applicationPath }, + crypto.from_hex(message), + ) + .then(array => new TextDecoder().decode(array)); + } + + return "command does not exist"; + }, +}; diff --git a/apps/cli/src/commands/live/ledgerSync.ts b/apps/cli/src/commands/live/ledgerSync.ts new file mode 100644 index 000000000000..d8c60fcd3b11 --- /dev/null +++ b/apps/cli/src/commands/live/ledgerSync.ts @@ -0,0 +1,160 @@ +import { getSdk } from "@ledgerhq/ledger-key-ring-protocol/index"; +import { CloudSyncSDK, UpdateEvent } from "@ledgerhq/live-wallet/cloudsync/index"; +import walletsync, { + liveSlug, + DistantState as LiveData, +} from "@ledgerhq/live-wallet/walletsync/index"; +import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess"; +import { getEnv } from "@ledgerhq/live-env"; + +export default { + description: "Ledger Sync command", + args: [ + { + name: "push", + type: Boolean, + desc: "Init member credentials for Ledger Key Ring Protocol", + }, + { + name: "pull", + type: Boolean, + desc: "Get or create a Ledger Key Ring Protocol Tree", + }, + { + name: "pubKey", + type: String, + desc: "pubkey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result", + }, + { + name: "privateKey", + type: String, + desc: "privatekey for Ledger Key Ring Protocol Tree retrieved from initMemberCredentials result", + }, + { + name: "rootId", + type: String, + desc: "The immutable id of the Tree root retrieved from getKeyRingTree result", + }, + { + name: "walletSyncEncryptionKey", + type: String, + desc: "The secret used to encrypt/decrypt the wallet sync data retrieved from getKeyRingTree result", + }, + { + name: "applicationPath", + type: String, + desc: "privatekey for Ledger Key Ring Protocol Tree from initMemberCredentials result", + }, + { + name: "data", + type: String, + desc: "data to be pushed to Ledger Sync", + }, + { + name: "version", + type: Number, + desc: "version of the data", + }, + { + name: "applicationId", + type: Number, + default: 16, + desc: "application identifier", + }, + { + name: "name", + type: String, + default: "CLI", + desc: "name of the instance", + }, + { + name: "apiBaseUrl", + type: String, + default: getEnv("TRUSTCHAIN_API_STAGING"), + desc: "api base url for Ledger Key Ring Protocol", + }, + { + name: "cloudSyncApiBaseUrl", + type: String, + default: getEnv("CLOUD_SYNC_API_STAGING"), + desc: "api base url for Cloud Sync", + }, + ], + job: ({ + push, + pull, + pubKey, + privateKey, + rootId, + walletSyncEncryptionKey, + applicationPath, + data, + version, + applicationId = 16, + name = "CLI", + apiBaseUrl = getEnv("TRUSTCHAIN_API_STAGING"), + cloudSyncApiBaseUrl = getEnv("CLOUD_SYNC_API_STAGING"), + }: Partial<{ + push: boolean; + pull: boolean; + pubKey: string; + privateKey: string; + rootId: string; + walletSyncEncryptionKey: string; + applicationPath: string; + data: string; + version: number; + applicationId: number; + name: string; + apiBaseUrl: string; + cloudSyncApiBaseUrl: string; + }>) => { + if (!applicationId) return "applicationId is required"; + if (!name) return "name is required"; + if (!apiBaseUrl) return "apiBaseUrl is required"; + if (!pubKey || !privateKey) return "pubKey and privateKey are required"; + if (!rootId) return "pubKey and privateKey are required"; + if (!walletSyncEncryptionKey) return "walletSyncEncryptionKey is required"; + if (!applicationPath) return "applicationPath is required"; + if (push && !data) return "data is required"; + + const context = { + applicationId, + name, + apiBaseUrl, + }; + const ledgerKeyRingProtocolSDK = getSdk(false, context, withDevice); + + const cloudSyncSDK = new CloudSyncSDK({ + apiBaseUrl: cloudSyncApiBaseUrl, + slug: liveSlug, + schema: walletsync.schema, + trustchainSdk: ledgerKeyRingProtocolSDK, + getCurrentVersion: () => version || 1, + saveNewUpdate: async (event: UpdateEvent) => { + console.log(event); + }, + }); + + if (push) { + return cloudSyncSDK + .push( + { rootId, walletSyncEncryptionKey, applicationPath }, + { pubkey: pubKey, privatekey: privateKey }, + JSON.parse(data!) as LiveData, + ) + .then(result => JSON.stringify(result, null, 2)); + } + + if (pull) { + return cloudSyncSDK + .pull( + { rootId, walletSyncEncryptionKey, applicationPath }, + { pubkey: pubKey, privatekey: privateKey }, + ) + .then(result => JSON.stringify(result, null, 2)); + } + + return "command does not exist"; + }, +}; diff --git a/apps/ledger-live-desktop/CHANGELOG.md b/apps/ledger-live-desktop/CHANGELOG.md index 382ab15b7fad..e8de8c36dfe1 100644 --- a/apps/ledger-live-desktop/CHANGELOG.md +++ b/apps/ledger-live-desktop/CHANGELOG.md @@ -1,5 +1,134 @@ # ledger-live-desktop +## 2.89.0 + +### Minor Changes + +- [#7870](https://github.com/LedgerHQ/ledger-live/pull/7870) [`1b3a21d`](https://github.com/LedgerHQ/ledger-live/commit/1b3a21d5d8496c42f4dec4116fdcf59ad6f038cd) Thanks [@marcotoniut-ledger](https://github.com/marcotoniut-ledger)! - ledger-live-desktop: Updated staking modal. Filtering per category. New copy and design + live-mobile: Updated staking modal. Filtering per category. New copy and design + @ledgerhq/icons-ui: Add book-graduation icon + @ledgerhq/types-live: Update schema of ethStakingProviders flag + @ledgerhq/native-ui: Add `xs` size to Button + +- [#8003](https://github.com/LedgerHQ/ledger-live/pull/8003) [`c9088c9`](https://github.com/LedgerHQ/ledger-live/commit/c9088c94a75d68ca3267a37c3059d1b8dce9a3fc) Thanks [@KVNLS](https://github.com/KVNLS)! - Fix app position with external display + +- [#7973](https://github.com/LedgerHQ/ledger-live/pull/7973) [`64d8546`](https://github.com/LedgerHQ/ledger-live/commit/64d854687369a63a77f3b31793b87af570e2f3c5) Thanks [@KVNLS](https://github.com/KVNLS)! - Fetch FF every 5 minutes for LLM & LLD + +- [#7964](https://github.com/LedgerHQ/ledger-live/pull/7964) [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7) Thanks [@KVNLS](https://github.com/KVNLS)! - Use Ledger Key Ring Protocol naming + +- [#8000](https://github.com/LedgerHQ/ledger-live/pull/8000) [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4) Thanks [@CremaFR](https://github.com/CremaFR)! - display name in swap history use cdn + +### Patch Changes + +- [#8073](https://github.com/LedgerHQ/ledger-live/pull/8073) [`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Revert solana priority fees + +- [#8014](https://github.com/LedgerHQ/ledger-live/pull/8014) [`b7311c4`](https://github.com/LedgerHQ/ledger-live/commit/b7311c4c773b188465560150932f0cdbceec42e0) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Add the platform OS to the params passed to earn to enable the correct braze environment + +- [#7995](https://github.com/LedgerHQ/ledger-live/pull/7995) [`e8cd9ce`](https://github.com/LedgerHQ/ledger-live/commit/e8cd9ce312f1ea8be7fb4d3d119fa16f98207068) Thanks [@LucasWerey](https://github.com/LucasWerey)! - add analytics console toggle in dev settings + +- [#8026](https://github.com/LedgerHQ/ledger-live/pull/8026) [`c7bc0d7`](https://github.com/LedgerHQ/ledger-live/commit/c7bc0d7ee558da193d60e692564dffca17f0287f) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add mocked generator braze CCs in dev settings + +- [#8074](https://github.com/LedgerHQ/ledger-live/pull/8074) [`389fa47`](https://github.com/LedgerHQ/ledger-live/commit/389fa47806680b6f8e99052f165860332aa00131) Thanks [@adammino-ledger](https://github.com/adammino-ledger)! - Fix on Yield button displayed for Bitcoin on the Account screen when not in stakePrograms + +- [#7891](https://github.com/LedgerHQ/ledger-live/pull/7891) [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add useCheckNftAccount Hook + +- [#8036](https://github.com/LedgerHQ/ledger-live/pull/8036) [`592449a`](https://github.com/LedgerHQ/ledger-live/commit/592449ac49433397edc91fc2bd50256301e03945) Thanks [@lpaquet-ledger](https://github.com/lpaquet-ledger)! - add TOS thorchain + +- [#7966](https://github.com/LedgerHQ/ledger-live/pull/7966) [`4b0d0f8`](https://github.com/LedgerHQ/ledger-live/commit/4b0d0f8b3694491143ea9307460384471ca93cc2) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add the hide inscription feature for ordinals + +- [#7965](https://github.com/LedgerHQ/ledger-live/pull/7965) [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Cardano fees warning + fix high fees issue + +- [#8012](https://github.com/LedgerHQ/ledger-live/pull/8012) [`82beaa0`](https://github.com/LedgerHQ/ledger-live/commit/82beaa0be485a48c4b28791e3bb65d59208741b0) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - add default parent account where missing + +- Updated dependencies [[`642c714`](https://github.com/LedgerHQ/ledger-live/commit/642c714d52eaaccb1b8ac3a2ee0391b641d19303), [`ced792c`](https://github.com/LedgerHQ/ledger-live/commit/ced792c37b42135f2b7596228c14ccd0783a803f), [`1b3a21d`](https://github.com/LedgerHQ/ledger-live/commit/1b3a21d5d8496c42f4dec4116fdcf59ad6f038cd), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba), [`0a16ae4`](https://github.com/LedgerHQ/ledger-live/commit/0a16ae4cb58ad9f2e67c7f3494b0dc52cb7423a1), [`6f0d39f`](https://github.com/LedgerHQ/ledger-live/commit/6f0d39f46ef5d3e24439421aa68dfe7aadcd1dbc), [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`9c6e2c4`](https://github.com/LedgerHQ/ledger-live/commit/9c6e2c4969832d9d55188ed03bbdfd79b43b7e63), [`a47e68b`](https://github.com/LedgerHQ/ledger-live/commit/a47e68b568a3b888a241c30345b4935557404215), [`4b0d0f8`](https://github.com/LedgerHQ/ledger-live/commit/4b0d0f8b3694491143ea9307460384471ca93cc2), [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7), [`3652e83`](https://github.com/LedgerHQ/ledger-live/commit/3652e83e02876856f1370cccab47f4272b71a7d3), [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7), [`3824e06`](https://github.com/LedgerHQ/ledger-live/commit/3824e06ba2c94bc0697d2a40d865efe766d1f102), [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4)]: + - @ledgerhq/types-live@6.52.1 + - @ledgerhq/live-common@34.11.0 + - @ledgerhq/live-env@2.4.0 + - @ledgerhq/coin-evm@2.4.0 + - @ledgerhq/live-nft-react@0.4.8 + - @ledgerhq/ledger-key-ring-protocol@0.5.0 + - @ledgerhq/live-nft@0.4.8 + - @ledgerhq/hw-ledger-key-ring-protocol@0.2.0 + - @ledgerhq/live-wallet@0.7.0 + - @ledgerhq/coin-bitcoin@0.8.3 + - @ledgerhq/coin-framework@0.18.3 + - @ledgerhq/coin-cosmos@0.1.4 + - @ledgerhq/domain-service@1.2.7 + - @ledgerhq/live-countervalues@0.2.8 + - @ledgerhq/live-countervalues-react@0.2.8 + - @ledgerhq/live-network@2.0.2 + - @ledgerhq/react-ui@0.16.2 + +## 2.89.0-next.2 + +### Patch Changes + +- [#8074](https://github.com/LedgerHQ/ledger-live/pull/8074) [`389fa47`](https://github.com/LedgerHQ/ledger-live/commit/389fa47806680b6f8e99052f165860332aa00131) Thanks [@adammino-ledger](https://github.com/adammino-ledger)! - Fix on Yield button displayed for Bitcoin on the Account screen when not in stakePrograms + +## 2.89.0-next.1 + +### Patch Changes + +- [#8073](https://github.com/LedgerHQ/ledger-live/pull/8073) [`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Revert solana priority fees + +- Updated dependencies [[`ea4edf3`](https://github.com/LedgerHQ/ledger-live/commit/ea4edf306a52fad556273afae7fd907f610c9aba)]: + - @ledgerhq/live-common@34.11.0-next.1 + +## 2.89.0-next.0 + +### Minor Changes + +- [#7870](https://github.com/LedgerHQ/ledger-live/pull/7870) [`1b3a21d`](https://github.com/LedgerHQ/ledger-live/commit/1b3a21d5d8496c42f4dec4116fdcf59ad6f038cd) Thanks [@marcotoniut-ledger](https://github.com/marcotoniut-ledger)! - ledger-live-desktop: Updated staking modal. Filtering per category. New copy and design + live-mobile: Updated staking modal. Filtering per category. New copy and design + @ledgerhq/icons-ui: Add book-graduation icon + @ledgerhq/types-live: Update schema of ethStakingProviders flag + @ledgerhq/native-ui: Add `xs` size to Button + +- [#8003](https://github.com/LedgerHQ/ledger-live/pull/8003) [`c9088c9`](https://github.com/LedgerHQ/ledger-live/commit/c9088c94a75d68ca3267a37c3059d1b8dce9a3fc) Thanks [@KVNLS](https://github.com/KVNLS)! - Fix app position with external display + +- [#7973](https://github.com/LedgerHQ/ledger-live/pull/7973) [`64d8546`](https://github.com/LedgerHQ/ledger-live/commit/64d854687369a63a77f3b31793b87af570e2f3c5) Thanks [@KVNLS](https://github.com/KVNLS)! - Fetch FF every 5 minutes for LLM & LLD + +- [#7964](https://github.com/LedgerHQ/ledger-live/pull/7964) [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7) Thanks [@KVNLS](https://github.com/KVNLS)! - Use Ledger Key Ring Protocol naming + +- [#8000](https://github.com/LedgerHQ/ledger-live/pull/8000) [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4) Thanks [@CremaFR](https://github.com/CremaFR)! - display name in swap history use cdn + +### Patch Changes + +- [#8014](https://github.com/LedgerHQ/ledger-live/pull/8014) [`b7311c4`](https://github.com/LedgerHQ/ledger-live/commit/b7311c4c773b188465560150932f0cdbceec42e0) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Add the platform OS to the params passed to earn to enable the correct braze environment + +- [#7995](https://github.com/LedgerHQ/ledger-live/pull/7995) [`e8cd9ce`](https://github.com/LedgerHQ/ledger-live/commit/e8cd9ce312f1ea8be7fb4d3d119fa16f98207068) Thanks [@LucasWerey](https://github.com/LucasWerey)! - add analytics console toggle in dev settings + +- [#8026](https://github.com/LedgerHQ/ledger-live/pull/8026) [`c7bc0d7`](https://github.com/LedgerHQ/ledger-live/commit/c7bc0d7ee558da193d60e692564dffca17f0287f) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add mocked generator braze CCs in dev settings + +- [#7891](https://github.com/LedgerHQ/ledger-live/pull/7891) [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3) Thanks [@mcayuelas-ledger](https://github.com/mcayuelas-ledger)! - Add useCheckNftAccount Hook + +- [#8036](https://github.com/LedgerHQ/ledger-live/pull/8036) [`592449a`](https://github.com/LedgerHQ/ledger-live/commit/592449ac49433397edc91fc2bd50256301e03945) Thanks [@lpaquet-ledger](https://github.com/lpaquet-ledger)! - add TOS thorchain + +- [#7966](https://github.com/LedgerHQ/ledger-live/pull/7966) [`4b0d0f8`](https://github.com/LedgerHQ/ledger-live/commit/4b0d0f8b3694491143ea9307460384471ca93cc2) Thanks [@LucasWerey](https://github.com/LucasWerey)! - Add the hide inscription feature for ordinals + +- [#7965](https://github.com/LedgerHQ/ledger-live/pull/7965) [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Cardano fees warning + fix high fees issue + +- [#8012](https://github.com/LedgerHQ/ledger-live/pull/8012) [`82beaa0`](https://github.com/LedgerHQ/ledger-live/commit/82beaa0be485a48c4b28791e3bb65d59208741b0) Thanks [@kallen-ledger](https://github.com/kallen-ledger)! - add default parent account where missing + +- Updated dependencies [[`642c714`](https://github.com/LedgerHQ/ledger-live/commit/642c714d52eaaccb1b8ac3a2ee0391b641d19303), [`ced792c`](https://github.com/LedgerHQ/ledger-live/commit/ced792c37b42135f2b7596228c14ccd0783a803f), [`1b3a21d`](https://github.com/LedgerHQ/ledger-live/commit/1b3a21d5d8496c42f4dec4116fdcf59ad6f038cd), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`0a16ae4`](https://github.com/LedgerHQ/ledger-live/commit/0a16ae4cb58ad9f2e67c7f3494b0dc52cb7423a1), [`6f0d39f`](https://github.com/LedgerHQ/ledger-live/commit/6f0d39f46ef5d3e24439421aa68dfe7aadcd1dbc), [`00cab1d`](https://github.com/LedgerHQ/ledger-live/commit/00cab1db1d67eb0cf35059eeeb9e2d8bd328f8f3), [`b0d535b`](https://github.com/LedgerHQ/ledger-live/commit/b0d535b72d9c6ac7e474de2b598bc4964a515d93), [`87b706c`](https://github.com/LedgerHQ/ledger-live/commit/87b706c8a807f14c72c7d47206e9ee767f50a04c), [`9c6e2c4`](https://github.com/LedgerHQ/ledger-live/commit/9c6e2c4969832d9d55188ed03bbdfd79b43b7e63), [`a47e68b`](https://github.com/LedgerHQ/ledger-live/commit/a47e68b568a3b888a241c30345b4935557404215), [`4b0d0f8`](https://github.com/LedgerHQ/ledger-live/commit/4b0d0f8b3694491143ea9307460384471ca93cc2), [`9032845`](https://github.com/LedgerHQ/ledger-live/commit/9032845a3cbadf40d545d6832e0280880e0be3d7), [`3652e83`](https://github.com/LedgerHQ/ledger-live/commit/3652e83e02876856f1370cccab47f4272b71a7d3), [`07a242d`](https://github.com/LedgerHQ/ledger-live/commit/07a242d9c54a4b70d9fec7ef390b8e8ab7de4df7), [`3824e06`](https://github.com/LedgerHQ/ledger-live/commit/3824e06ba2c94bc0697d2a40d865efe766d1f102), [`d962cf1`](https://github.com/LedgerHQ/ledger-live/commit/d962cf13667a383b77a1d30bf26bec27702d9af4)]: + - @ledgerhq/types-live@6.52.1-next.0 + - @ledgerhq/live-common@34.11.0-next.0 + - @ledgerhq/live-env@2.4.0-next.0 + - @ledgerhq/coin-evm@2.4.0-next.0 + - @ledgerhq/live-nft-react@0.4.8-next.0 + - @ledgerhq/ledger-key-ring-protocol@0.5.0-next.0 + - @ledgerhq/live-nft@0.4.8-next.0 + - @ledgerhq/hw-ledger-key-ring-protocol@0.2.0-next.0 + - @ledgerhq/live-wallet@0.7.0-next.0 + - @ledgerhq/coin-bitcoin@0.8.3-next.0 + - @ledgerhq/coin-framework@0.18.3-next.0 + - @ledgerhq/coin-cosmos@0.1.4-next.0 + - @ledgerhq/domain-service@1.2.7-next.0 + - @ledgerhq/live-countervalues@0.2.8-next.0 + - @ledgerhq/live-countervalues-react@0.2.8-next.0 + - @ledgerhq/live-network@2.0.2-next.0 + - @ledgerhq/react-ui@0.16.2-next.0 + ## 2.88.0 ### Minor Changes diff --git a/apps/ledger-live-desktop/RELEASE_NOTES.md b/apps/ledger-live-desktop/RELEASE_NOTES.md index eabcedb394fb..a307b111bfe1 100644 --- a/apps/ledger-live-desktop/RELEASE_NOTES.md +++ b/apps/ledger-live-desktop/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +# 2.89.0 + +This release includes small security improvements, UI tweaks, and minor bug fixes. + # 2.87.1 This release includes small security improvements, UI tweaks, and minor bug fixes. diff --git a/apps/ledger-live-desktop/TERMS.md b/apps/ledger-live-desktop/TERMS.md index 6932e88281a3..32002bb86a1b 100644 --- a/apps/ledger-live-desktop/TERMS.md +++ b/apps/ledger-live-desktop/TERMS.md @@ -134,6 +134,7 @@ With Ledger Live, you can (including without limitation) - [FTX Terms of service](https://help.ftx.com/hc/en-us/articles/360024788391-FTX-Terms-of-Service) - [Paraswap Terms of service](https://psdocs.fra1.digitaloceanspaces.com/tos_v2.pdf) - [Exodus Terms and conditions](https://www.exodus.com/terms/) +- [THORChain Terms and conditions](https://tos.swapkit.dev/) **5.2.2 No warranty.** Ledger is not responsible for the content, accuracy, security, availability, any performance, or failure to perform of the Third Party Services or any issue in relation with the use of Third Party Services. Ledger does not provide any guarantees that access to Third Party Services will not be interrupted or that there will be no delays, failures, errors, omissions, corruption or loss of transmitted information, data or funds, and Ledger shall not be liable for any such Third Party Services. You agree to use the Third Party Services at your own risk. It is your responsibility to review the third party’s terms and policies before using a Third Party Service. Third Party Services may not be available in all languages and may not be appropriate or available for use in any particular location. To the extent you choose to use such Third Party Services, you are solely responsible for compliance with any applicable laws in relation to such use. In addition, Ledger reserves the right to block access to these Third Party Services through Ledger Live in particular, but not exclusively, in the event of non-compliance with the applicable regulations by the Third Party partner. We retain the exclusive right to suspend, remove, or cancel the availability of any such Third Party Service for any reason and without prior notice. diff --git a/apps/ledger-live-desktop/package.json b/apps/ledger-live-desktop/package.json index 55678a2771a7..cf6920f32c02 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.88.0", + "version": "2.89.0", "scripts": { "start:prod": "electron ./.webpack/main.bundle.js", "start": "cross-env NODE_ENV=development node ./tools/main.js", @@ -66,7 +66,7 @@ "@ledgerhq/hw-transport-node-hid-singleton": "workspace:^", "@ledgerhq/hw-transport-node-speculos-http": "workspace:^", "@ledgerhq/hw-transport-vault": "workspace:^", - "@ledgerhq/hw-trustchain": "workspace:^", + "@ledgerhq/hw-ledger-key-ring-protocol": "workspace:^", "@ledgerhq/live-common": "workspace:^", "@ledgerhq/live-config": "workspace:^", "@ledgerhq/live-countervalues": "workspace:^", @@ -78,7 +78,7 @@ "@ledgerhq/live-wallet": "workspace:^", "@ledgerhq/logs": "workspace:^", "@ledgerhq/react-ui": "workspace:^", - "@ledgerhq/trustchain": "workspace:^", + "@ledgerhq/ledger-key-ring-protocol": "workspace:^", "@ledgerhq/types-cryptoassets": "workspace:^", "@ledgerhq/types-devices": "workspace:^", "@ledgerhq/types-live": "workspace:^", diff --git a/apps/ledger-live-desktop/src/config/urls.ts b/apps/ledger-live-desktop/src/config/urls.ts index ee2bf428d1b3..083c32dc3c43 100644 --- a/apps/ledger-live-desktop/src/config/urls.ts +++ b/apps/ledger-live-desktop/src/config/urls.ts @@ -168,6 +168,11 @@ export const urls = { editEvmTx: { learnMore: "https://support.ledger.com/article/9756122596765-zd", }, + ledgerAcademy: { + whatIsEthereumRestaking: "https://www.ledger.com/academy/what-is-ethereum-restaking", + ethereumStakingHowToStakeEth: + "https://www.ledger.com/academy/ethereum-staking-how-to-stake-eth", + }, ledgerByFigmentTC: "https://cdn.figment.io/legal/Current%20Ledger_Online%20Staking%20Delgation%20Services%20Agreement.pdf", ens: "https://support.ledger.com/article/9710787581469-zd", diff --git a/apps/ledger-live-desktop/src/main/window-lifecycle.ts b/apps/ledger-live-desktop/src/main/window-lifecycle.ts index 9dbd25c67b9f..ea4e4bac1991 100644 --- a/apps/ledger-live-desktop/src/main/window-lifecycle.ts +++ b/apps/ledger-live-desktop/src/main/window-lifecycle.ts @@ -114,7 +114,13 @@ function restorePosition( ) { x = bounds.x; y = bounds.y; + } else { + // If the saved position is not valid, move the window to the primary display. + const primaryDisplay = screen.getPrimaryDisplay().workArea; + x = primaryDisplay.x; + y = primaryDisplay.y; } + // If the saved size is still valid, use it. if (bounds.width <= area.width || bounds.height <= area.height) { width = bounds.width; diff --git a/apps/ledger-live-desktop/src/newArch/components/ContextMenu/CollectibleContextMenu.tsx b/apps/ledger-live-desktop/src/newArch/components/ContextMenu/CollectibleContextMenu.tsx index 0791c9c545a6..526d3d2f2067 100644 --- a/apps/ledger-live-desktop/src/newArch/components/ContextMenu/CollectibleContextMenu.tsx +++ b/apps/ledger-live-desktop/src/newArch/components/ContextMenu/CollectibleContextMenu.tsx @@ -16,6 +16,8 @@ type Props = { leftClick?: boolean; goBackToAccount?: boolean; typeOfCollectible: CollectibleType; + inscriptionId?: string; + inscriptionName?: string; }; export default function CollectionContextMenu({ @@ -26,6 +28,8 @@ export default function CollectionContextMenu({ leftClick, goBackToAccount = false, typeOfCollectible, + inscriptionId, + inscriptionName, }: Props) { const { t } = useTranslation(); const dispatch = useDispatch(); @@ -36,6 +40,8 @@ export default function CollectionContextMenu({ collectionName, collectionAddress, account, + inscriptionId, + inscriptionName, dispatch, setDrawer, history, 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 befe1ce2f99a..ff1d8206cd96 100644 --- a/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts +++ b/apps/ledger-live-desktop/src/newArch/components/ContextMenu/createContextMenuItems.ts @@ -12,6 +12,8 @@ type Props = { collectionAddress: string; collectionName?: string | null; goBackToAccount?: boolean; + inscriptionId?: string; + inscriptionName?: string; typeOfCollectible: CollectibleType; dispatch: Dispatch; setDrawer: () => void; @@ -24,6 +26,8 @@ export function createContextMenuItems({ collectionName, collectionAddress, account, + inscriptionId, + inscriptionName, dispatch, setDrawer, history, @@ -52,5 +56,27 @@ export function createContextMenuItems({ }, ]; } + if (typeOfCollectible === CollectibleTypeEnum.Inscriptions) { + return [ + { + key: "hide", + label: t("ordinals.inscriptions.hide"), + Icon: IconsLegacy.NoneMedium, + callback: () => + dispatch( + openModal("MODAL_HIDE_INSCRIPTION", { + inscriptionName: String(inscriptionName), + inscriptionId: String(inscriptionId), + onClose: () => { + if (goBackToAccount) { + setDrawer(); + history.replace(`account/${account.id}`); + } + }, + }), + ), + }, + ]; + } return []; } diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/DetailsDrawer/Actions.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/DetailsDrawer/Actions.tsx index 6f84b66e4955..66e4f6262562 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/DetailsDrawer/Actions.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/DetailsDrawer/Actions.tsx @@ -5,23 +5,33 @@ import { useTranslation } from "react-i18next"; import { ExternalViewerButton } from "LLD/features/Collectibles/components/DetailDrawer/components"; import { SimpleHashNft } from "@ledgerhq/live-nft/api/types"; import { Account } from "@ledgerhq/types-live"; +import { useHideInscriptions } from "LLD/features/Collectibles/hooks/useHideInscriptions"; type ActionsProps = { inscription: SimpleHashNft; account: Account; + onModalClose: () => void; }; -const Actions: React.FC = ({ inscription, account }) => { +const Actions: React.FC = ({ inscription, account, onModalClose }) => { const { t } = useTranslation(); + const { openConfirmHideInscriptionModal } = useHideInscriptions(); + + const onClick = () => { + openConfirmHideInscriptionModal( + inscription.name || inscription.contract.name || "", + String(inscription.extra_metadata?.ordinal_details?.inscription_id), + onModalClose, + ); + }; + return ( + + + )} + /> + ); +}; +export default Body; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/HideModal/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/HideModal/index.tsx new file mode 100644 index 000000000000..745d4df848d7 --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/HideModal/index.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import Modal from "~/renderer/components/Modal"; +import Body from "./Body"; + +const HideNftCollectionModal = () => ( + ( + { + onClose?.(); + data?.onClose?.(); + }} + /> + )} + /> +); +export default HideNftCollectionModal; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/Item/index.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/Item/index.tsx index b9c404527346..d0b946e5fd8b 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/Item/index.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/Item/index.tsx @@ -4,10 +4,14 @@ import TableRow from "LLD/features/Collectibles/components/Collection/TableRow"; import { GroupedNftOrdinals } from "@ledgerhq/live-nft-react/index"; import { findCorrespondingSat } from "LLD/features/Collectibles/utils/findCorrespondingSat"; import { processRareSat } from "../helpers"; +import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collectibles"; +import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types"; +import CollectionContextMenu from "LLD/components/ContextMenu/CollectibleContextMenu"; type ItemProps = { isLoading: boolean; inscriptionsGroupedWithRareSats: GroupedNftOrdinals[]; + account: BitcoinAccount; } & InscriptionsItemProps; const Item: React.FC = ({ @@ -17,6 +21,7 @@ const Item: React.FC = ({ media, nftId, inscriptionsGroupedWithRareSats, + account, onClick, }) => { const correspondingRareSat = findCorrespondingSat(inscriptionsGroupedWithRareSats, nftId); @@ -25,15 +30,23 @@ const Item: React.FC = ({ }, [correspondingRareSat]); return ( - + + + ); }; diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/helpers.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/helpers.ts index 695f0a214b1d..775becabc731 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/helpers.ts +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/helpers.ts @@ -7,7 +7,7 @@ export function getInscriptionsData( ) { return inscriptions.map(item => ({ tokenName: item.name || item.contract.name || "", - nftId: item.nft_id, + nftId: String(item.extra_metadata?.ordinal_details?.inscription_id), collectionName: item.collection.name, media: { uri: item.image_url || item.previews?.image_small_url, 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 index e6269cb4034b..96a42869d625 100644 --- 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 @@ -14,12 +14,14 @@ import { CollectibleTypeEnum } from "LLD/features/Collectibles/types/enum/Collec import Button from "~/renderer/components/Button"; import { useTranslation } from "react-i18next"; import { GroupedNftOrdinals } from "@ledgerhq/live-nft-react/index"; +import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types"; type ViewProps = ReturnType & { isLoading: boolean; isError: boolean; error: Error | null; inscriptionsGroupedWithRareSats: GroupedNftOrdinals[]; + account: BitcoinAccount; onReceive: () => void; }; @@ -29,6 +31,7 @@ type Props = { isError: boolean; error: Error | null; inscriptionsGroupedWithRareSats: GroupedNftOrdinals[]; + account: BitcoinAccount; onReceive: () => void; onInscriptionClick: (inscription: SimpleHashNft) => void; }; @@ -40,6 +43,7 @@ const View: React.FC = ({ inscriptions, error, inscriptionsGroupedWithRareSats, + account, onShowMore, onReceive, }) => { @@ -57,6 +61,7 @@ const View: React.FC = ({ {hasInscriptions && inscriptions.map((item, index) => ( = ({ isError, error, inscriptionsGroupedWithRareSats, + account, onReceive, onInscriptionClick, }) => ( @@ -92,6 +98,7 @@ const Inscriptions: React.FC = ({ isLoading={isLoading} isError={isError} error={error} + account={account} onReceive={onReceive} inscriptionsGroupedWithRareSats={inscriptionsGroupedWithRareSats} {...useInscriptionsModel({ inscriptions, onInscriptionClick })} 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 index 431e3234b68f..6bddf828d1bc 100644 --- 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 @@ -22,11 +22,17 @@ export const useInscriptionsModel = ({ inscriptions, onInscriptionClick }: Props useState(initialDisplayedObjects); useEffect(() => { - if (displayedObjects.length === 0) { - if (items.length > 3) setDisplayShowMore(true); + const filteredDisplayedObjects = displayedObjects.filter(displayedObject => + items.some(item => item.nftId === displayedObject.nftId), + ); + if (filteredDisplayedObjects.length !== displayedObjects.length) { + setDisplayedObjects(items.slice(0, filteredDisplayedObjects.length + 1)); + } else if (displayedObjects.length === 0 && items.length > 3) { + setDisplayShowMore(true); setDisplayedObjects(items.slice(0, 3)); } - }, [items, displayedObjects.length]); + if (displayedObjects.length === items.length) setDisplayShowMore(false); + }, [items, displayedObjects]); const onShowMore = () => { setDisplayedObjects(prevDisplayedObjects => { 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 index 372d2c1a5e18..5664ebebbc9e 100644 --- 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 @@ -36,6 +36,7 @@ const View: React.FC = ({ onReceive={onReceive} onInscriptionClick={onInscriptionClick} inscriptionsGroupedWithRareSats={inscriptionsGroupedWithRareSats} + account={account} /> diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/useBitcoinAccountModel.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/useBitcoinAccountModel.ts index c1c8d0ad620b..162e52665131 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/useBitcoinAccountModel.ts +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/useBitcoinAccountModel.ts @@ -7,6 +7,7 @@ import { openModal } from "~/renderer/actions/modals"; import { setHasSeenOrdinalsDiscoveryDrawer } from "~/renderer/actions/settings"; import { hasSeenOrdinalsDiscoveryDrawerSelector } from "~/renderer/reducers/settings"; import { findCorrespondingSat } from "LLD/features/Collectibles/utils/findCorrespondingSat"; +import { useHideInscriptions } from "LLD/features/Collectibles/hooks/useHideInscriptions"; interface Props { account: BitcoinAccount; @@ -14,6 +15,7 @@ interface Props { export const useBitcoinAccountModel = ({ account }: Props) => { const dispatch = useDispatch(); + const hasSeenDiscoveryDrawer = useSelector(hasSeenOrdinalsDiscoveryDrawerSelector); const [selectedInscription, setSelectedInscription] = useState(null); const [correspondingRareSat, setCorrespondingRareSat] = useState< @@ -24,6 +26,8 @@ export const useBitcoinAccountModel = ({ account }: Props) => { account, }); + const { filterInscriptions } = useHideInscriptions(); + const filteredInscriptions = filterInscriptions(inscriptions); const [isDrawerOpen, setIsDrawerOpen] = useState(!hasSeenDiscoveryDrawer); useEffect(() => { @@ -56,7 +60,7 @@ export const useBitcoinAccountModel = ({ account }: Props) => { return { rareSats, - inscriptions, + inscriptions: filteredInscriptions, rest, isDrawerOpen, selectedInscription, diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/bitcoinPage.test.tsx b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/bitcoinPage.test.tsx index a34984d96302..9af4e6aeab3b 100644 --- a/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/bitcoinPage.test.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/__integration__/bitcoinPage.test.tsx @@ -6,6 +6,7 @@ import { render, screen, waitFor } from "tests/testUtils"; import { BitcoinPage } from "./shared"; import { openURL } from "~/renderer/linking"; import { DeviceModelId } from "@ledgerhq/devices"; +import { INITIAL_STATE as INITIAL_STATE_SETTINGS } from "~/renderer/reducers/settings"; jest.mock( "electron", @@ -22,20 +23,22 @@ describe("displayBitcoinPage", () => { const { user } = render(, { initialState: { settings: { + ...INITIAL_STATE_SETTINGS, hasSeenOrdinalsDiscoveryDrawer: true, devicesModelList: [DeviceModelId.stax, DeviceModelId.europa], + hiddenOrdinalsAsset: [], }, }, }); await waitFor(() => expect(screen.getByText(/the great war #3695/i)).toBeVisible()); - await waitFor(() => expect(screen.getByText(/see more inscriptions/i)).toBeVisible()); + expect(screen.getByText(/see more inscriptions/i)).toBeVisible(); await user.click(screen.getByText(/see more inscriptions/i)); await user.click(screen.getByText(/see more inscriptions/i)); - await waitFor(() => expect(screen.getByText(/bitcoin puppet #71/i)).toBeVisible()); - await waitFor(() => expect(screen.queryAllByTestId(/raresaticon-pizza-0/i)).toHaveLength(2)); - await user.hover(screen.queryAllByTestId(/raresaticon-pizza-0/i)[0]); - await waitFor(() => expect(screen.getByText(/papa john's pizza/i)).toBeVisible()); + expect(screen.getByText(/bitcoin puppet #71/i)).toBeVisible(); + expect(screen.getByTestId(/raresaticon-pizza-0/i)).toBeVisible(); + await user.hover(screen.getByTestId(/raresaticon-pizza-0/i)); + expect(screen.getByText(/papa john's pizza/i)).toBeVisible(); }); it("should open discovery drawer when it is the first time feature is activated", async () => { @@ -50,16 +53,34 @@ describe("displayBitcoinPage", () => { const { user } = render(, { initialState: { settings: { + ...INITIAL_STATE_SETTINGS, hasSeenOrdinalsDiscoveryDrawer: true, devicesModelList: [DeviceModelId.stax, DeviceModelId.europa], + hiddenOrdinalsAsset: [], }, }, }); await waitFor(() => expect(screen.getByText(/the great war #3695/i)).toBeVisible()); await user.click(screen.getByText(/the great war #3695/i)); - await expect(screen.getByText(/hide/i)).toBeVisible(); - // sat name - await expect(screen.getByText(/dlngbapxjdv/i)).toBeVisible(); + expect(screen.getByText(/hide/i)).toBeVisible(); + expect(screen.getByText(/dlngbapxjdv/i)).toBeVisible(); + }); + + it("should open context menu", async () => { + const { user } = render(, { + initialState: { + settings: { + ...INITIAL_STATE_SETTINGS, + hasSeenOrdinalsDiscoveryDrawer: true, + devicesModelList: [DeviceModelId.stax, DeviceModelId.europa], + hiddenOrdinalsAsset: [], + }, + }, + }); + + await waitFor(() => expect(screen.getByText(/the great war #3695/i)).toBeVisible()); + await user.pointer({ keys: "[MouseRight>]", target: screen.getByText(/the great war #3695/i) }); + expect(screen.getByText(/hide inscription/i)); }); }); diff --git a/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useHideInscriptions.ts b/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useHideInscriptions.ts new file mode 100644 index 000000000000..879a29e7ee3b --- /dev/null +++ b/apps/ledger-live-desktop/src/newArch/features/Collectibles/hooks/useHideInscriptions.ts @@ -0,0 +1,48 @@ +import { SimpleHashNft } from "@ledgerhq/live-nft/api/types"; +import { useDispatch, useSelector } from "react-redux"; +import { openModal } from "~/renderer/actions/modals"; +import { hideOrdinalsAsset, unhideOrdinalsAsset } from "~/renderer/actions/settings"; +import { hiddenOrdinalsAssetSelector } from "~/renderer/reducers/settings"; + +export const useHideInscriptions = () => { + const dispatch = useDispatch(); + const hiddenOrdinalAssets = useSelector(hiddenOrdinalsAssetSelector); + + const filterInscriptions = (inscriptions: SimpleHashNft[]) => { + return inscriptions.filter(inscription => { + return !hiddenOrdinalAssets.includes( + String(inscription.extra_metadata?.ordinal_details?.inscription_id), + ); + }); + }; + + const hideInscription = (inscriptionId: string) => { + dispatch(hideOrdinalsAsset(inscriptionId)); + }; + + const unHideInscription = (inscriptionId: string) => { + dispatch(unhideOrdinalsAsset(inscriptionId)); + }; + + const openConfirmHideInscriptionModal = ( + inscriptionName: string, + inscriptionId: string, + onModalClose: () => void, + ) => { + dispatch( + openModal("MODAL_HIDE_INSCRIPTION", { + inscriptionName, + inscriptionId, + onClose: () => onModalClose(), + }), + ); + }; + + return { + filterInscriptions, + hideInscription, + unHideInscription, + openConfirmHideInscriptionModal, + hiddenOrdinalAssets, + }; +}; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/__tests__/shared.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/__tests__/shared.tsx index 03152bfc5f87..6f25c1143a82 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/__tests__/shared.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/__tests__/shared.tsx @@ -1,7 +1,7 @@ import React from "react"; -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; import WalletSyncRow from "~/renderer/screens/settings/sections/General/WalletSync"; -import { getSdk } from "@ledgerhq/trustchain/index"; +import { getSdk } from "@ledgerhq/ledger-key-ring-protocol/index"; import { EMPTY } from "rxjs"; import { Flow, initialStateWalletSync, Step } from "~/renderer/reducers/walletSync"; import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams"; 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 fea26ed934c7..6fcb93d0db2c 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 @@ -2,17 +2,17 @@ import { memberCredentialsSelector, setTrustchain, trustchainSelector, -} from "@ledgerhq/trustchain/store"; +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useDispatch, useSelector } from "react-redux"; import { setFlow } from "~/renderer/actions/walletSync"; import { Flow, Step } from "~/renderer/reducers/walletSync"; import { useTrustchainSdk } from "./useTrustchainSdk"; -import { TrustchainResult, TrustchainResultType } from "@ledgerhq/trustchain/types"; +import { TrustchainResult, TrustchainResultType } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useCallback, useEffect, useRef, useState } from "react"; import { TrustchainAlreadyInitialized, TrustchainAlreadyInitializedWithOtherSeed, -} from "@ledgerhq/trustchain/errors"; +} from "@ledgerhq/ledger-key-ring-protocol/errors"; export function useAddMember({ device }: { device: Device | null }) { const dispatch = useDispatch(); diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useDestroyTrustchain.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useDestroyTrustchain.ts index 27e3d5d642dd..b1be931f3798 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useDestroyTrustchain.ts +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useDestroyTrustchain.ts @@ -4,7 +4,7 @@ import { trustchainSelector, resetTrustchainStore, memberCredentialsSelector, -} from "@ledgerhq/trustchain/store"; +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useMutation } from "@tanstack/react-query"; import { setFlow } from "~/renderer/actions/walletSync"; import { Flow, Step } from "~/renderer/reducers/walletSync"; 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 a7b46608b976..20f88c23a678 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,4 +1,4 @@ -import { trustchainSelector } from "@ledgerhq/trustchain/store"; +import { trustchainSelector } from "@ledgerhq/ledger-key-ring-protocol/store"; import { useDispatch, useSelector } from "react-redux"; import { setFlow } from "~/renderer/actions/walletSync"; import { 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 f87b2d9e14fb..32656e62ffa9 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 @@ -1,11 +1,14 @@ -import { memberCredentialsSelector, trustchainSelector } from "@ledgerhq/trustchain/store"; +import { + memberCredentialsSelector, + trustchainSelector, +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useSelector } from "react-redux"; import { useTrustchainSdk } from "./useTrustchainSdk"; 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"; +import { TrustchainNotFound } from "@ledgerhq/ledger-key-ring-protocol/errors"; export function useGetMembers() { const sdk = useTrustchainSdk(); diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInitMemberCredentials.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInitMemberCredentials.ts index 92544d7becdf..987c6deee9d3 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInitMemberCredentials.ts +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useInitMemberCredentials.ts @@ -1,4 +1,7 @@ -import { memberCredentialsSelector, setMemberCredentials } from "@ledgerhq/trustchain/store"; +import { + memberCredentialsSelector, + setMemberCredentials, +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useCallback, useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useTrustchainSdk } from "./useTrustchainSdk"; 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 24d390df3a41..ae4e189c3706 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 @@ -1,12 +1,14 @@ import { useQueries, UseQueryResult } from "@tanstack/react-query"; import { QueryKey } from "./type.hooks"; -import getTrustchainApi, { StatusAPIResponse as TrustchainStatus } from "@ledgerhq/trustchain/api"; +import getTrustchainApi, { + StatusAPIResponse as TrustchainStatus, +} from "@ledgerhq/ledger-key-ring-protocol/api"; import getCloudSyncApi, { StatusAPIResponse as CloudSyncStatus, } 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 { trustchainSelector } from "@ledgerhq/ledger-key-ring-protocol/store"; import { useSelector } from "react-redux"; import { walletSelector } from "~/renderer/reducers/wallet"; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useOnTrustchainRefreshNeeded.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useOnTrustchainRefreshNeeded.ts index b1f771272a32..a02dfd3c052e 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useOnTrustchainRefreshNeeded.ts +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useOnTrustchainRefreshNeeded.ts @@ -1,8 +1,12 @@ import { useCallback } from "react"; import { useDispatch } from "react-redux"; -import { MemberCredentials, Trustchain, TrustchainSDK } from "@ledgerhq/trustchain/types"; -import { setTrustchain, resetTrustchainStore } from "@ledgerhq/trustchain/store"; -import { TrustchainEjected } from "@ledgerhq/trustchain/errors"; +import { + MemberCredentials, + Trustchain, + TrustchainSDK, +} from "@ledgerhq/ledger-key-ring-protocol/types"; +import { setTrustchain, resetTrustchainStore } from "@ledgerhq/ledger-key-ring-protocol/store"; +import { TrustchainEjected } from "@ledgerhq/ledger-key-ring-protocol/errors"; import { log } from "@ledgerhq/logs"; export function useOnTrustchainRefreshNeeded( 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 54bf875c2282..8fe0d5d10521 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,12 +1,12 @@ import { useCallback, useState } from "react"; -import { createQRCodeHostInstance } from "@ledgerhq/trustchain/qrcode/index"; +import { createQRCodeHostInstance } from "@ledgerhq/ledger-key-ring-protocol/qrcode/index"; import { InvalidDigitsError, NoTrustchainInitialized, QRCodeWSClosed, TrustchainAlreadyInitialized, -} from "@ledgerhq/trustchain/errors"; -import { MemberCredentials } from "@ledgerhq/trustchain/types"; +} from "@ledgerhq/ledger-key-ring-protocol/errors"; +import { MemberCredentials } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useDispatch, useSelector } from "react-redux"; import { setFlow, setQrCodePinCode } from "~/renderer/actions/walletSync"; import { Flow, Step } from "~/renderer/reducers/walletSync"; @@ -14,7 +14,7 @@ import { trustchainSelector, memberCredentialsSelector, setTrustchain, -} from "@ledgerhq/trustchain/store"; +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useTrustchainSdk } from "./useTrustchainSdk"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams"; 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 4caa5eb26a2b..8653a93a5487 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 @@ -2,14 +2,14 @@ import { memberCredentialsSelector, setTrustchain, trustchainSelector, -} from "@ledgerhq/trustchain/store"; +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { useDispatch, useSelector } from "react-redux"; import { setFlow } from "~/renderer/actions/walletSync"; import { Flow, Step } from "~/renderer/reducers/walletSync"; import { useTrustchainSdk } from "./useTrustchainSdk"; -import { TrustchainMember, Trustchain } from "@ledgerhq/trustchain/types"; +import { TrustchainMember, Trustchain } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useCallback, useEffect, useRef, useState } from "react"; -import { TrustchainNotAllowed } from "@ledgerhq/trustchain/errors"; +import { TrustchainNotAllowed } from "@ledgerhq/ledger-key-ring-protocol/errors"; type Props = { device: Device | null; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRestoreTrustchain.ts b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRestoreTrustchain.ts index bcce8916144f..206c35038808 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRestoreTrustchain.ts +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/hooks/useRestoreTrustchain.ts @@ -2,8 +2,8 @@ import { memberCredentialsSelector, trustchainSelector, setTrustchain, -} from "@ledgerhq/trustchain/store"; -import { Trustchain, MemberCredentials } from "@ledgerhq/trustchain/types"; +} from "@ledgerhq/ledger-key-ring-protocol/store"; +import { Trustchain, MemberCredentials } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useQuery } from "@tanstack/react-query"; import { useDispatch, useSelector } from "react-redux"; import { QueryKey } from "./type.hooks"; 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 005b22b69803..13c4d57e02ed 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,12 +1,12 @@ import { useMemo } from "react"; import { getEnv } from "@ledgerhq/live-env"; -import { getSdk } from "@ledgerhq/trustchain/index"; +import { getSdk } from "@ledgerhq/ledger-key-ring-protocol/index"; import { withDevice } from "@ledgerhq/live-common/hw/deviceAccess"; import { trustchainLifecycle } from "@ledgerhq/live-wallet/walletsync/index"; import { useStore } from "react-redux"; import { walletSelector } from "~/renderer/reducers/wallet"; import { walletSyncStateSelector } from "@ledgerhq/live-wallet/store"; -import { TrustchainSDK } from "@ledgerhq/trustchain/types"; +import { TrustchainSDK } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import getWalletSyncEnvironmentParams from "@ledgerhq/live-common/walletSync/getEnvironmentParams"; import { useInstanceName } from "./useInstanceName"; 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 ea01985aa4d2..9bb85995b0bc 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 @@ -13,7 +13,10 @@ import walletsync, { } from "@ledgerhq/live-wallet/walletsync/index"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { walletSelector } from "~/renderer/reducers/wallet"; -import { memberCredentialsSelector, trustchainSelector } from "@ledgerhq/trustchain/store"; +import { + memberCredentialsSelector, + trustchainSelector, +} from "@ledgerhq/ledger-key-ring-protocol/store"; import { State } from "~/renderer/reducers"; import { cache as bridgeCache } from "~/renderer/bridge/cache"; import { 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 d897437a2fd6..b6700d6d9387 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 @@ -1,4 +1,4 @@ -import { resetTrustchainStore } from "@ledgerhq/trustchain/store"; +import { resetTrustchainStore } from "@ledgerhq/ledger-key-ring-protocol/store"; import { useDispatch } from "react-redux"; import { ErrorType } from "./type.hooks"; import { setFlow } from "~/renderer/actions/walletSync"; @@ -7,7 +7,7 @@ import { TrustchainEjected, TrustchainNotAllowed, TrustchainOutdated, -} from "@ledgerhq/trustchain/errors"; +} from "@ledgerhq/ledger-key-ring-protocol/errors"; import { useRestoreTrustchain } from "./useRestoreTrustchain"; import { useTrustchainSdk } from "./useTrustchainSdk"; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/openOrInstall.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/openOrInstall.tsx index 815aa740a953..6dc47788f32b 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/openOrInstall.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/DeviceActions/openOrInstall.tsx @@ -5,7 +5,7 @@ import { mockedEventEmitter } from "~/renderer/components/debug/DebugMock"; import connectApp from "@ledgerhq/live-common/hw/connectApp"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { createAction } from "@ledgerhq/live-common/hw/actions/app"; -import { TRUSTCHAIN_APP_NAME } from "@ledgerhq/hw-trustchain"; +import { TRUSTCHAIN_APP_NAME } from "@ledgerhq/hw-ledger-key-ring-protocol"; const action = createAction(getEnv("MOCK") ? mockedEventEmitter : connectApp); 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 8784d72bbf1d..9b498768c826 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 @@ -5,9 +5,9 @@ import { AnalyticsPage, useLedgerSyncAnalytics } from "../../hooks/useLedgerSync import TrackPage from "~/renderer/analytics/TrackPage"; import { TinyCard } from "../../components/TinyCard"; import { useInstances } from "./useInstances"; -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; import { useDispatch, useSelector } from "react-redux"; -import { memberCredentialsSelector } from "@ledgerhq/trustchain/store"; +import { memberCredentialsSelector } from "@ledgerhq/ledger-key-ring-protocol/store"; import styled from "styled-components"; import { setFlow } from "~/renderer/actions/walletSync"; import { Flow, Step } from "~/renderer/reducers/walletSync"; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/03-DeleteInstanceWithTrustchain.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/03-DeleteInstanceWithTrustchain.tsx index 4c1024287996..e6ec6b614049 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/03-DeleteInstanceWithTrustchain.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/03-DeleteInstanceWithTrustchain.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; import FollowStepsOnDevice from "../DeviceActions/FollowStepsOnDevice"; import ErrorDisplay from "~/renderer/components/ErrorDisplay"; import { useRemoveMember } from "LLD/features/WalletSync/hooks/useRemoveMember"; diff --git a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalErrorStep.tsx b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalErrorStep.tsx index 030997a7ac99..6ee77ce4deee 100644 --- a/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalErrorStep.tsx +++ b/apps/ledger-live-desktop/src/newArch/features/WalletSync/screens/ManageInstances/04-DeletionFinalErrorStep.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Error } from "../../components/Error"; import { useTranslation } from "react-i18next"; import { Flex } from "@ledgerhq/react-ui"; -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; export type FinalStepProps = { instance: TrustchainMember | null; 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 ce29ff8ba098..5bbacb47d74a 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 @@ -8,7 +8,7 @@ import DeviceActionInstanceStep from "./02-DeviceActionInstanceStep"; import DeleteInstanceWithTrustchain from "./03-DeleteInstanceWithTrustchain"; import DeletionFinalStep from "./04-DeletionFinalStep"; import { DeletionError, ErrorReason } from "./04-DeletionError"; -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; import DeletionErrorFinalStep from "./04-DeletionFinalErrorStep"; const WalletSyncManageInstances = forwardRef((_props, ref) => { diff --git a/apps/ledger-live-desktop/src/renderer/Default.tsx b/apps/ledger-live-desktop/src/renderer/Default.tsx index cbb19db999b6..0bed65b6e48a 100644 --- a/apps/ledger-live-desktop/src/renderer/Default.tsx +++ b/apps/ledger-live-desktop/src/renderer/Default.tsx @@ -55,6 +55,7 @@ import { import { isLocked as isLockedSelector } from "~/renderer/reducers/application"; import { useAutoDismissPostOnboardingEntryPoint } from "@ledgerhq/live-common/postOnboarding/hooks/index"; import { setShareAnalytics, setSharePersonalizedRecommendations } from "./actions/settings"; +import useEnv from "@ledgerhq/live-common/hooks/useEnv"; const PlatformCatalog = lazy(() => import("~/renderer/screens/platform")); const Dashboard = lazy(() => import("~/renderer/screens/dashboard")); @@ -190,6 +191,7 @@ export default function Default() { const history = useHistory(); const hasCompletedOnboarding = useSelector(hasCompletedOnboardingSelector); const accounts = useSelector(accountsSelector); + const analyticsConsoleActive = useEnv("ANALYTICS_CONSOLE"); useAccountsWithFundsListener(accounts, updateIdentify); useListenToHidDevices(); @@ -394,7 +396,7 @@ export default function Default() { - {process.env.ANALYTICS_CONSOLE ? : null} + {analyticsConsoleActive ? : null} ); } diff --git a/apps/ledger-live-desktop/src/renderer/actions/settings.ts b/apps/ledger-live-desktop/src/renderer/actions/settings.ts index ad3a94577590..e90520966f32 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/settings.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/settings.ts @@ -218,6 +218,11 @@ export const hideNftCollection = (collectionId: string) => ({ type: "HIDE_NFT_COLLECTION", payload: collectionId, }); +export const hideOrdinalsAsset = (inscriptionId: string) => ({ + type: "HIDE_ORDINALS_ASSET", + payload: inscriptionId, +}); + export const setLastSeenCustomImage = (lastSeenCustomImage: { imageSize: number; imageHash: string; @@ -247,6 +252,10 @@ export const unhideNftCollection = (collectionId: string) => ({ type: "UNHIDE_NFT_COLLECTION", payload: collectionId, }); +export const unhideOrdinalsAsset = (inscriptionId: string) => ({ + type: "UNHIDE_ORDINALS_ASSET", + payload: inscriptionId, +}); type FetchSettings = (a: SettingsState) => (a: Dispatch>) => void; export const fetchSettings: FetchSettings = (settings: SettingsState) => dispatch => { dispatch({ diff --git a/apps/ledger-live-desktop/src/renderer/actions/trustchain.ts b/apps/ledger-live-desktop/src/renderer/actions/trustchain.ts index 24f58b5ed611..3f7ca82ef9ee 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/trustchain.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/trustchain.ts @@ -1,5 +1,5 @@ import { Dispatch } from "redux"; -import { importTrustchainStoreState } from "@ledgerhq/trustchain/store"; +import { importTrustchainStoreState } from "@ledgerhq/ledger-key-ring-protocol/store"; import { getKey } from "~/renderer/storage"; export const fetchTrustchain = () => async (dispatch: Dispatch) => { diff --git a/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts b/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts index 6c857dc5e9f6..2c575836552d 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/walletSync.ts @@ -1,4 +1,4 @@ -import { TrustchainMember } from "@ledgerhq/trustchain/types"; +import { TrustchainMember } from "@ledgerhq/ledger-key-ring-protocol/types"; import { ChangeFlowPayload } from "../reducers/walletSync"; export const setFlow = (payload: ChangeFlowPayload) => ({ diff --git a/apps/ledger-live-desktop/src/renderer/components/BalanceInfos/index.tsx b/apps/ledger-live-desktop/src/renderer/components/BalanceInfos/index.tsx index 263b9c23b14e..fab152c2e45e 100644 --- a/apps/ledger-live-desktop/src/renderer/components/BalanceInfos/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/BalanceInfos/index.tsx @@ -142,6 +142,13 @@ export default function BalanceInfos({ [counterValueId, flattenedAccounts], ); + const parentAccount = useMemo(() => { + if (defaultAccount?.type === "TokenAccount") { + const parentId = defaultAccount.parentId; + return flattenedAccounts.find(a => a.id === parentId); + } + }, [defaultAccount, flattenedAccounts]); + // Remove "SWAP" and "BUY" redundant buttons when portafolio exchange banner is available const portfolioExchangeBanner = useFeature("portfolioExchangeBanner"); const onBuy = useCallback(() => { @@ -160,9 +167,10 @@ export default function BalanceInfos({ state: { from: history.location.pathname, defaultAccount, + defaultParentAccount: parentAccount, }, }); - }, [history, defaultAccount]); + }, [history, defaultAccount, parentAccount]); const ref = useRef(null); const { width } = useResize(ref); diff --git a/apps/ledger-live-desktop/src/renderer/components/Carousel/helpers.tsx b/apps/ledger-live-desktop/src/renderer/components/Carousel/helpers.tsx index 3543a018ccfe..456fdc240ea8 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Carousel/helpers.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Carousel/helpers.tsx @@ -92,14 +92,13 @@ export const useDefaultSlides = (): { : currentCard.id && dispatch(setDismissedContentCards({ id: currentCard.id, timestamp: Date.now() })); setCachedContentCards(cachedContentCards.filter(n => n.id !== currentCard.id)); - dispatch(setPortfolioCards(portfolioCards.filter(n => n.id !== slide.id))); } + dispatch(setPortfolioCards(portfolioCards.filter(n => n.id !== slide.id))); } } }, [portfolioCards, cachedContentCards, isTrackedUser, dispatch], ); - const logSlideClick = useCallback( (cardId: string) => { const currentCard = cachedContentCards.find(card => card.id === cardId); diff --git a/apps/ledger-live-desktop/src/renderer/components/FirebaseRemoteConfig.tsx b/apps/ledger-live-desktop/src/renderer/components/FirebaseRemoteConfig.tsx index 49a7a162b94e..dda9d5a5abe3 100644 --- a/apps/ledger-live-desktop/src/renderer/components/FirebaseRemoteConfig.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/FirebaseRemoteConfig.tsx @@ -134,8 +134,8 @@ export const FirebaseRemoteConfigProvider = ({ } }; fetchAndActivateConfig(); - // 1 hour fetch interval. TODO: make this configurable - const intervalId = window.setInterval(fetchAndActivateConfig, 1 * 60 * 60 * 1000); + // 5 minutes fetch interval. TODO: make this configurable + const intervalId = window.setInterval(fetchAndActivateConfig, 5 * 60 * 1000); return () => clearInterval(intervalId); }, [setConfig]); diff --git a/apps/ledger-live-desktop/src/renderer/families/bitcoin/AccountHeaderManageActions.ts b/apps/ledger-live-desktop/src/renderer/families/bitcoin/AccountHeaderManageActions.ts new file mode 100644 index 000000000000..fe1939152ef4 --- /dev/null +++ b/apps/ledger-live-desktop/src/renderer/families/bitcoin/AccountHeaderManageActions.ts @@ -0,0 +1,67 @@ +import { getMainAccount } from "@ledgerhq/live-common/account/index"; + +import { useTranslation } from "react-i18next"; +import { useHistory } from "react-router"; +import { track } from "~/renderer/analytics/segment"; +import { stakeDefaultTrack } from "~/renderer/screens/stake/constants"; +import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types"; +import { TokenAccount } from "@ledgerhq/types-live"; +import IconCoins from "~/renderer/icons/Coins"; +import useFeature from "@ledgerhq/live-common/featureFlags/useFeature"; + +type Props = { + account: BitcoinAccount | TokenAccount; + parentAccount: BitcoinAccount | undefined | null; +}; + +const AccountHeaderActions = ({ account, parentAccount }: Props) => { + const stakeProgramsFeatureFlag = useFeature("stakePrograms"); + const listFlag = stakeProgramsFeatureFlag?.params?.list ?? []; + const stakeProgramsEnabled = stakeProgramsFeatureFlag?.enabled ?? false; + const availableOnStake = stakeProgramsEnabled && listFlag.includes("bitcoin"); + const history = useHistory(); + const { t } = useTranslation(); + const mainAccount = getMainAccount(account, parentAccount); + const { + bitcoinResources, + currency: { id: currencyId }, + } = mainAccount; + if (!bitcoinResources || parentAccount || currencyId !== "bitcoin") return null; + + const stakeOnClick = () => { + const value = "/platform/acre"; + + track("button_clicked2", { + ...stakeDefaultTrack, + delegation: "stake", + page: "Page Account", + button: "delegate", + provider: "Acre", + currency: "BTC", + }); + history.push({ + pathname: value, + state: { + accountId: account.id, + returnTo: `/account/${account.id}`, + }, + }); + }; + + return availableOnStake + ? [ + { + key: "Stake", + icon: IconCoins, + label: t("accounts.contextMenu.yield"), + event: "button_clicked2", + eventProperties: { + button: "stake", + }, + onClick: stakeOnClick, + }, + ] + : []; +}; + +export default AccountHeaderActions; diff --git a/apps/ledger-live-desktop/src/renderer/families/bitcoin/index.ts b/apps/ledger-live-desktop/src/renderer/families/bitcoin/index.ts index d65009a89e20..321e5b73ff1f 100644 --- a/apps/ledger-live-desktop/src/renderer/families/bitcoin/index.ts +++ b/apps/ledger-live-desktop/src/renderer/families/bitcoin/index.ts @@ -2,12 +2,14 @@ import "./live-common-setup"; import sendAmountFields from "./SendAmountFields"; import sendRecipientFields from "./SendRecipientFields"; import StepReceiveFundsPostAlert from "./StepReceiveFundsPostAlert"; +import accountHeaderManageActions from "./AccountHeaderManageActions"; import { BitcoinFamily } from "./types"; const family: BitcoinFamily = { sendAmountFields, sendRecipientFields, StepReceiveFundsPostAlert, + accountHeaderManageActions, }; export default family; diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/EthStakingModalBody.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/EthStakingModalBody.tsx index 1ec6c8d1f475..4138e3230941 100644 --- a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/EthStakingModalBody.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/EthStakingModalBody.tsx @@ -1,59 +1,26 @@ -import { Flex, Text } from "@ledgerhq/react-ui"; -import { Account } from "@ledgerhq/types-live"; -import React, { useCallback, useState } from "react"; -import { useHistory } from "react-router-dom"; -import BigNumber from "bignumber.js"; -import { useTranslation } from "react-i18next"; - -import { appendQueryParamsToDappURL } from "@ledgerhq/live-common/platform/utils/appendQueryParamsToDappURL"; -import { getCryptoCurrencyById } from "@ledgerhq/live-common/currencies/index"; import { LiveAppManifest } from "@ledgerhq/live-common/platform/types"; +import { appendQueryParamsToDappURL } from "@ledgerhq/live-common/platform/utils/appendQueryParamsToDappURL"; +import { Flex } from "@ledgerhq/react-ui"; +import { Account, EthStakingProvider } from "@ledgerhq/types-live"; +import React, { useCallback } from "react"; +import { useHistory } from "react-router-dom"; import { track } from "~/renderer/analytics/segment"; -import CheckBox from "~/renderer/components/CheckBox"; -import EthStakeIllustration from "~/renderer/icons/EthStakeIllustration"; - -import { - CheckBoxContainer, - LOCAL_STORAGE_KEY_PREFIX, -} from "~/renderer/modals/Receive/steps/StepReceiveStakingFlow"; -import { ListProvider, ListProviders } from "./types"; +import { ProviderItem } from "./component/ProviderItem"; import { getTrackProperties } from "./utils/getTrackProperties"; -import ProviderItem from "./component/ProviderItem"; - -const ethMagnitude = getCryptoCurrencyById("ethereum").units[0].magnitude; - -const ETH_LIMIT = BigNumber(32).times(BigNumber(10).pow(ethMagnitude)); - -// Comparison fns for sorting providers by minimum ETH required -const ascending = (a: ListProvider, b: ListProvider) => (a?.min || 0) - (b?.min || 0); -const descending = (a: ListProvider, b: ListProvider) => (b?.min || 0) - (a?.min || 0); - type Props = { account: Account; - singleProviderRedirectMode?: boolean; onClose?: () => void; - hasCheckbox?: boolean; source?: string; - listProviders?: ListProviders; + providers: EthStakingProvider[]; }; export type StakeOnClickProps = { - provider: ListProvider; + provider: EthStakingProvider; manifest: LiveAppManifest; }; - -export function EthStakingModalBody({ - hasCheckbox = false, - singleProviderRedirectMode = true, - source, - onClose, - account, - listProviders = [], -}: Props) { - const { t } = useTranslation(); +export function EthStakingModalBody({ source, onClose, account, providers }: Props) { const history = useHistory(); - const [doNotShowAgain, setDoNotShowAgain] = useState(false); const stakeOnClick = useCallback( ({ @@ -66,6 +33,7 @@ export function EthStakingModalBody({ button: providerConfigID, ...getTrackProperties({ value, modal: source }), }); + history.push({ pathname: value, ...(customDappUrl ? { customDappUrl } : {}), @@ -78,69 +46,13 @@ export function EthStakingModalBody({ [history, account.id, onClose, source], ); - const redirectIfOnlyProvider = useCallback( - (stakeOnClickProps: StakeOnClickProps) => { - if (singleProviderRedirectMode && listProviders.length === 1) { - stakeOnClick(stakeOnClickProps); - } - }, - [singleProviderRedirectMode, listProviders.length, stakeOnClick], - ); - - const checkBoxOnChange = useCallback(() => { - const value = !doNotShowAgain; - global.localStorage.setItem(`${LOCAL_STORAGE_KEY_PREFIX}${account?.currency?.id}`, `${value}`); - setDoNotShowAgain(value); - track("button_clicked2", { - button: "not_show", - ...getTrackProperties({ value, modal: source }), - }); - }, [doNotShowAgain, account?.currency?.id, source]); - - const hasMinValidatorEth = account.spendableBalance.isGreaterThan(ETH_LIMIT); - - const listProvidersSorted = listProviders.sort(hasMinValidatorEth ? descending : ascending); - return ( - - - - {t("ethereum.stake.title")} - - {listProviders.length <= 1 && ( - - - - )} - - {t("ethereum.stake.subTitle")} - - - - - {listProvidersSorted.map(item => ( - - - - ))} + + {providers.map(x => ( + + - {hasCheckbox && ( - - - - )} - + ))} ); } diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/component/ProviderItem.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/component/ProviderItem.tsx index 24dead9da680..0009e312fee5 100644 --- a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/component/ProviderItem.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/component/ProviderItem.tsx @@ -1,94 +1,113 @@ import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; -import { Flex, Icon, Tag as TagCore, Text } from "@ledgerhq/react-ui"; -import React, { useCallback, useEffect, useMemo } from "react"; +import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; +import { CryptoIcon, Flex, Icon, Text } from "@ledgerhq/react-ui"; +import { EthStakingProvider } from "@ledgerhq/types-live"; +import React, { useCallback, useMemo } from "react"; import { useTranslation } from "react-i18next"; import styled, { DefaultTheme, StyledComponent } from "styled-components"; +import ProviderIcon from "~/renderer/components/ProviderIcon"; import { StakeOnClickProps } from "../EthStakingModalBody"; -import { StakingIcon } from "../StakingIcon"; -import { ListProvider } from "../types"; -import { useLocalLiveAppManifest } from "@ledgerhq/live-common/wallet-api/LocalLiveAppProvider/index"; -export const Container: StyledComponent< - "div", - DefaultTheme, - Record, - never -> = styled(Flex)` +const IconContainer = styled.div( + ({ theme }) => ` + display: flex; + justify-content: center; + align-items: center; + width: ${theme.space[6]}px; + height: ${theme.space[6]}px; + border-radius: 100%; + background-color: ${theme.colors.opacityDefault.c05}; + margin-top: ${theme.space[3]}px; +`, +); + +function StakingIcon({ icon }: { icon?: string }) { + if (!icon) { + return null; + } + + const [iconName, iconType] = icon.split(":"); + + // if no icon type then treat as "normal" icon. + if (!iconType) { + return ( + + + + ); + } + if (iconType === "crypto") { + return ; + } + if (iconType === "provider") { + return ( + + + + ); + } + + return null; +} + +const Container: StyledComponent<"div", DefaultTheme, Record, never> = styled( + Flex, +)` cursor: pointer; - border-radius: 8px; + background-color: ${p => p.theme.colors.opacityDefault.c05}; :hover { background-color: ${p => p.theme.colors.primary.c10}; } `; -export const Tag = styled(TagCore)` - padding: 3px 6px; - > span { - font-size: 11px; - text-transform: none; - font-weight: bold; - line-height: 11.66px; - } -`; - -type Props = { - provider: ListProvider; +interface Props { + provider: EthStakingProvider; stakeOnClick(_: StakeOnClickProps): void; - redirectIfOnlyProvider(_: StakeOnClickProps): void; -}; +} -const ProviderItem = ({ provider, stakeOnClick, redirectIfOnlyProvider }: Props) => { - const { t, i18n } = useTranslation(); +export const ProviderItem = ({ provider, stakeOnClick }: Props) => { + const { t } = useTranslation(); const localManifest = useLocalLiveAppManifest(provider.liveAppId); const remoteManifest = useRemoteLiveAppManifest(provider.liveAppId); const manifest = useMemo(() => remoteManifest || localManifest, [localManifest, remoteManifest]); - const hasTag = !!provider?.min && i18n.exists(`ethereum.stake.${provider.id}.tag`); - - useEffect(() => { - if (manifest) redirectIfOnlyProvider({ provider, manifest }); - }, [redirectIfOnlyProvider, provider, manifest]); - - const stakeLink = useCallback(() => { - if (manifest) stakeOnClick({ provider, manifest }); + const handleClick = useCallback(() => { + if (manifest) { + stakeOnClick({ provider, manifest }); + } }, [provider, stakeOnClick, manifest]); return ( - - - - {t(`ethereum.stake.${provider.id}.title`)} - - {hasTag && ( - - {t(`ethereum.stake.${provider.id}.tag`)} - - )} - - + + + {t(`ethereum.stake.provider.${provider.id}.title`)} + - {t(`ethereum.stake.${provider.id}.description`)} + {provider.lst + ? t("ethereum.stake.lst") + : provider.min + ? t("ethereum.stake.requiredMinimum", { + min: provider.min, + }) + : t("ethereum.stake.noMinimum")} - - + + + {t(`ethereum.stake.rewardsStrategy.${provider.rewardsStrategy}`)} + ); }; - -export default ProviderItem; diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/index.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/index.tsx index 8d258c038ff1..a337cefbd5e2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/evm/StakeFlowModal/index.tsx @@ -1,23 +1,79 @@ -import React from "react"; -import { Account } from "@ledgerhq/types-live"; +import { getCryptoCurrencyById } from "@ledgerhq/live-common/currencies/index"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; -import Modal, { ModalBody } from "~/renderer/components/Modal"; -import { Flex } from "@ledgerhq/react-ui"; +import { Box, Button, Flex, Icons, Text } from "@ledgerhq/react-ui"; +import { Account, EthStakingProvider, EthStakingProviderCategory } from "@ledgerhq/types-live"; +import BigNumber from "bignumber.js"; +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useTheme } from "styled-components"; +import { urls } from "~/config/urls"; +import { track } from "~/renderer/analytics/segment"; import TrackPage from "~/renderer/analytics/TrackPage"; +import Modal from "~/renderer/components/Modal"; +import EthStakeIllustration from "~/renderer/icons/EthStakeIllustration"; +import { openURL } from "~/renderer/linking"; import { EthStakingModalBody } from "./EthStakingModalBody"; +import { Footer, Header, IconButton, ScrollableContainer, SHADOW_HEIGHT } from "./styles"; -type Props = { +const ethMagnitude = getCryptoCurrencyById("ethereum").units[0].magnitude; + +const BUTTON_CLICKED_TRACK_EVENT = "button_clicked"; + +const ETH_LIMIT = BigNumber(32).times(BigNumber(10).pow(ethMagnitude)); + +// Comparison fns for sorting providers by minimum ETH required +const ascending = (a: EthStakingProvider, b: EthStakingProvider) => (a?.min ?? 0) - (b?.min ?? 0); +const descending = (a: EthStakingProvider, b: EthStakingProvider) => (b?.min ?? 0) - (a?.min ?? 0); + +type Option = EthStakingProviderCategory | "all"; +const OPTION_VALUES: Option[] = ["all", "liquid", "protocol", "pooling", "restaking"] as const; + +export interface Props { account: Account; - singleProviderRedirectMode?: boolean; /** Analytics source */ source?: string; hasCheckbox?: boolean; -}; +} + +const MODAL_WIDTH = 500; + +export const StakeModal = ({ account, source }: Props) => { + const { t } = useTranslation(); + const { colors } = useTheme(); + + const hasMinValidatorEth = account.spendableBalance.isGreaterThan(ETH_LIMIT); -const StakingModal = ({ account, hasCheckbox, singleProviderRedirectMode, source }: Props) => { const ethStakingProviders = useFeature("ethStakingProviders"); const providers = ethStakingProviders?.params?.listProvider; + const [selected, setSelected] = useState