diff --git a/.changeset/tender-laws-itch.md b/.changeset/angry-apples-study.md similarity index 56% rename from .changeset/tender-laws-itch.md rename to .changeset/angry-apples-study.md index ea11ff93bf77..29dbbbda939f 100644 --- a/.changeset/tender-laws-itch.md +++ b/.changeset/angry-apples-study.md @@ -2,4 +2,4 @@ "ledger-live-desktop": patch --- -Update ethereum staking icon +Remove Cardano Poolcost diff --git a/.changeset/brown-lions-speak.md b/.changeset/brown-lions-speak.md deleted file mode 100644 index 1451fd76e6dc..000000000000 --- a/.changeset/brown-lions-speak.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": patch ---- - -Ensure we reset the storage correctly in the PTXWebPlayer diff --git a/.changeset/chilly-elephants-call.md b/.changeset/chilly-elephants-call.md new file mode 100644 index 000000000000..48695bd83494 --- /dev/null +++ b/.changeset/chilly-elephants-call.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/native-ui": patch +--- + +Upgrade peerDependency react-native-reanimated to 3.3.0, devDependency expo to expo SDK 49 and metro to 0.79.0 diff --git a/.changeset/chilly-shoes-do.md b/.changeset/chilly-shoes-do.md new file mode 100644 index 000000000000..31f4d0230271 --- /dev/null +++ b/.changeset/chilly-shoes-do.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +remove source query params includes in featureflags diff --git a/.changeset/clever-ligers-jam.md b/.changeset/clever-ligers-jam.md new file mode 100644 index 000000000000..db33dbaf00b6 --- /dev/null +++ b/.changeset/clever-ligers-jam.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Search input Market was refreshing for each input diff --git a/.changeset/cold-rats-sell.md b/.changeset/cold-rats-sell.md new file mode 100644 index 000000000000..ba88abb26316 --- /dev/null +++ b/.changeset/cold-rats-sell.md @@ -0,0 +1,6 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +--- + +NFT screen/Stax: only display "custom lock screen" option if the user has connected a Stax once diff --git a/.changeset/hungry-pianos-vanish.md b/.changeset/dull-shrimps-wonder.md similarity index 57% rename from .changeset/hungry-pianos-vanish.md rename to .changeset/dull-shrimps-wonder.md index 5dc73d5ff144..ee8c4b5b4139 100644 --- a/.changeset/hungry-pianos-vanish.md +++ b/.changeset/dull-shrimps-wonder.md @@ -2,4 +2,4 @@ "@ledgerhq/cryptoassets": minor --- -CAL update +Add new data from dynamic CAL diff --git a/.changeset/early-snakes-whisper.md b/.changeset/early-snakes-whisper.md new file mode 100644 index 000000000000..4bc58cb29524 --- /dev/null +++ b/.changeset/early-snakes-whisper.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": patch +--- + +Upgrade dev dependency react-native to 0.72.3 diff --git a/.changeset/quick-olives-grab.md b/.changeset/early-yaks-protect.md similarity index 50% rename from .changeset/quick-olives-grab.md rename to .changeset/early-yaks-protect.md index 4c7276aaca23..0389cce78c16 100644 --- a/.changeset/quick-olives-grab.md +++ b/.changeset/early-yaks-protect.md @@ -2,4 +2,4 @@ "@ledgerhq/live-common": patch --- -fix wallet-api complete exchange logic +Handle txs without auth_info diff --git a/.changeset/empty-taxis-jog.md b/.changeset/empty-taxis-jog.md new file mode 100644 index 000000000000..80dd9ecc1ce2 --- /dev/null +++ b/.changeset/empty-taxis-jog.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +improve ble pairing deep links diff --git a/.changeset/five-monkeys-juggle.md b/.changeset/five-monkeys-juggle.md deleted file mode 100644 index 48ddea74c10f..000000000000 --- a/.changeset/five-monkeys-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": patch ---- - -Add Entry point to CEX with feature flag diff --git a/.changeset/fluffy-penguins-jump.md b/.changeset/fluffy-penguins-jump.md new file mode 100644 index 000000000000..8cc75852a08c --- /dev/null +++ b/.changeset/fluffy-penguins-jump.md @@ -0,0 +1,17 @@ +--- +"dummy-wallet-app": patch +"dummy-live-app": patch +"@ledgerhq/crypto-icons-ui": patch +"webpack.js-example": patch +"ledger-live-desktop": patch +"live-mobile": patch +"@ledgerhq/live-common": patch +"@ledgerhq/native-ui": patch +"@ledgerhq/icons-ui": patch +"@ledgerhq/react-ui": patch +"@ledgerhq/domain-service": patch +"web-tools": patch +"@ledgerhq/live-cli": patch +--- + +Update react to react 18 diff --git a/.changeset/forty-balloons-invite.md b/.changeset/forty-balloons-invite.md new file mode 100644 index 000000000000..01f18ba759d2 --- /dev/null +++ b/.changeset/forty-balloons-invite.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +display appropriate device image in change language prompt drawer diff --git a/.changeset/four-camels-notice.md b/.changeset/four-camels-notice.md new file mode 100644 index 000000000000..22d6868ae3d0 --- /dev/null +++ b/.changeset/four-camels-notice.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Fix string display in lockscreen diff --git a/.changeset/young-toes-clap.md b/.changeset/friendly-cycles-watch.md similarity index 65% rename from .changeset/young-toes-clap.md rename to .changeset/friendly-cycles-watch.md index d7a29cbc6aa5..a4d47a70ea94 100644 --- a/.changeset/young-toes-clap.md +++ b/.changeset/friendly-cycles-watch.md @@ -1,8 +1,7 @@ --- "@ledgerhq/types-live": patch "ledger-live-desktop": patch -"live-mobile": patch "@ledgerhq/live-common": patch --- -Typed useFeature hook +Add feature_ptx_swap_live_app feature flag and logic diff --git a/.changeset/fuzzy-windows-dance.md b/.changeset/fuzzy-windows-dance.md new file mode 100644 index 000000000000..932ef16b7c97 --- /dev/null +++ b/.changeset/fuzzy-windows-dance.md @@ -0,0 +1,7 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +"@ledgerhq/live-common": patch +--- + +Refactor FeatureFlagsProvider and take into account new signature of useFeature (can return null) diff --git a/.changeset/gentle-plants-dress.md b/.changeset/gentle-plants-dress.md new file mode 100644 index 000000000000..4dd594699ec1 --- /dev/null +++ b/.changeset/gentle-plants-dress.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Upgrade react-native to 0.72.3 (also closely related dependencies such as expo SDK to expo 49, react-native-reanimated to 3.3.0, @react-native-community/cli to 11.3.7) diff --git a/.changeset/giant-guests-refuse.md b/.changeset/giant-guests-refuse.md new file mode 100644 index 000000000000..8df69de2eed5 --- /dev/null +++ b/.changeset/giant-guests-refuse.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/coin-evm": patch +--- + +return error when tx from tokenAccount has no amount diff --git a/.changeset/long-schools-live.md b/.changeset/giant-wasps-exist.md similarity index 62% rename from .changeset/long-schools-live.md rename to .changeset/giant-wasps-exist.md index 6e846d6728d0..de7493093d8d 100644 --- a/.changeset/long-schools-live.md +++ b/.changeset/giant-wasps-exist.md @@ -3,4 +3,4 @@ "@ledgerhq/live-common": patch --- -Save swap history wallet api exchange +Fix confirmation message for swap web app diff --git a/.changeset/gold-hats-relax.md b/.changeset/gold-hats-relax.md new file mode 100644 index 000000000000..9afaa2276f07 --- /dev/null +++ b/.changeset/gold-hats-relax.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-cli": patch +--- + +Fixes in getAddress and bot command diff --git a/.changeset/gold-pants-sniff.md b/.changeset/gold-pants-sniff.md deleted file mode 100644 index 06d31393bf9d..000000000000 --- a/.changeset/gold-pants-sniff.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@ledgerhq/hw-app-eth": patch ---- - -Fixing hexBuffer helper for EIP712 signature not padding byte strings with 0 diff --git a/.changeset/gorgeous-items-shave.md b/.changeset/gorgeous-items-shave.md new file mode 100644 index 000000000000..a200aea1127a --- /dev/null +++ b/.changeset/gorgeous-items-shave.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Tap and drag to see price over time on graph is buggy on LLM diff --git a/.changeset/great-tomatoes-punch.md b/.changeset/great-tomatoes-punch.md deleted file mode 100644 index 40340a1c0a75..000000000000 --- a/.changeset/great-tomatoes-punch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"ledger-live-desktop": patch ---- - -Update learn more link for cosmos redelegation banner to point to cosmos page instead of ethereum page. diff --git a/.changeset/grumpy-flowers-enjoy.md b/.changeset/grumpy-flowers-enjoy.md deleted file mode 100644 index fc231ea1f265..000000000000 --- a/.changeset/grumpy-flowers-enjoy.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"ledger-live-desktop": minor -"live-mobile": minor ---- - -Fix swap issue when estimating and editing fees diff --git a/.changeset/happy-melons-taste.md b/.changeset/happy-melons-taste.md new file mode 100644 index 000000000000..245bdaafc84a --- /dev/null +++ b/.changeset/happy-melons-taste.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Update wording on Lock Screen for Stax diff --git a/.changeset/healthy-dots-give.md b/.changeset/healthy-dots-give.md new file mode 100644 index 000000000000..7d0d55a97eca --- /dev/null +++ b/.changeset/healthy-dots-give.md @@ -0,0 +1,6 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +--- + +Passed currency param on recover redirection diff --git a/.changeset/itchy-points-argue.md b/.changeset/itchy-points-argue.md new file mode 100644 index 000000000000..d997367990c9 --- /dev/null +++ b/.changeset/itchy-points-argue.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/coin-evm": patch +--- + +Fix swap-web-app fees diff --git a/.changeset/large-pets-divide.md b/.changeset/large-pets-divide.md new file mode 100644 index 000000000000..1a867f1e2376 --- /dev/null +++ b/.changeset/large-pets-divide.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": patch +--- + +include smallest denomination in swap request diff --git a/.changeset/large-sloths-reply.md b/.changeset/large-sloths-reply.md new file mode 100644 index 000000000000..5e876fab1764 --- /dev/null +++ b/.changeset/large-sloths-reply.md @@ -0,0 +1,6 @@ +--- +"ledger-live-desktop": minor +"@ledgerhq/live-common": minor +--- + +Update buy and sell service providers API endpoint; move logic to find if currency can be bought or sold into RampCatalogProvider and expose methods to get the list of providers or whether a given currency is supported; refactor to use ids instead of tickers. diff --git a/.changeset/light-ants-hang.md b/.changeset/light-ants-hang.md new file mode 100644 index 000000000000..722a09adae43 --- /dev/null +++ b/.changeset/light-ants-hang.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Update Stax wording + add oldVersion -> newVersion to firmware update screen diff --git a/.changeset/light-planes-cry.md b/.changeset/light-planes-cry.md deleted file mode 100644 index cee27b161351..000000000000 --- a/.changeset/light-planes-cry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": minor ---- - -Add a deeplinking state in redux to inform the AuthPass component not to lock when app is temporarily backgrounded by ptx player deeplinks. diff --git a/.changeset/little-papayas-nail.md b/.changeset/little-papayas-nail.md deleted file mode 100644 index 4b0bb63dd1ef..000000000000 --- a/.changeset/little-papayas-nail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@ledgerhq/live-common": minor ---- - -Add loading state to useGasOptions hook to be used by UI while gasOptions are being fetched diff --git a/.changeset/metal-bottles-add.md b/.changeset/metal-bottles-add.md new file mode 100644 index 000000000000..36acd7b95553 --- /dev/null +++ b/.changeset/metal-bottles-add.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": patch +--- + +Correct hedera estimated fees to allow max spendable to work as intended diff --git a/.changeset/metal-coats-hug.md b/.changeset/metal-coats-hug.md new file mode 100644 index 000000000000..f8641d21dcee --- /dev/null +++ b/.changeset/metal-coats-hug.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Update My Ledger provider wording in Experimental feature diff --git a/.changeset/mighty-birds-mate.md b/.changeset/mighty-birds-mate.md new file mode 100644 index 000000000000..7df422b6245a --- /dev/null +++ b/.changeset/mighty-birds-mate.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +QR Code scan during Send paste address in input diff --git a/.changeset/mighty-doors-visit.md b/.changeset/mighty-doors-visit.md deleted file mode 100644 index 3f9d4c3bdfc9..000000000000 --- a/.changeset/mighty-doors-visit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"ledger-live-desktop": patch ---- - -Fix Stax onboarding early security checks: infinite loading state for locked device diff --git a/.changeset/neat-colts-glow.md b/.changeset/neat-colts-glow.md deleted file mode 100644 index 2707de10ffa0..000000000000 --- a/.changeset/neat-colts-glow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": patch ---- - -change ui button device select restore flow diff --git a/.changeset/neat-dots-travel.md b/.changeset/neat-dots-travel.md new file mode 100644 index 000000000000..73242bf16264 --- /dev/null +++ b/.changeset/neat-dots-travel.md @@ -0,0 +1,5 @@ +--- +"@actions/upload-images": major +--- + +switch provider to s3 instead of imgur diff --git a/.changeset/nice-cobras-obey.md b/.changeset/nice-cobras-obey.md new file mode 100644 index 000000000000..854289f10486 --- /dev/null +++ b/.changeset/nice-cobras-obey.md @@ -0,0 +1,6 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +--- + +Add account wallet id conversion for buy deeplinks diff --git a/.changeset/nine-cooks-drop.md b/.changeset/nine-cooks-drop.md deleted file mode 100644 index 11c8e17ebee2..000000000000 --- a/.changeset/nine-cooks-drop.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@ledgerhq/coin-evm": minor ---- - -Add gasOption serialisation and deserialisation to evm transactions diff --git a/.changeset/old-moons-add.md b/.changeset/old-moons-add.md new file mode 100644 index 000000000000..e2d237139b85 --- /dev/null +++ b/.changeset/old-moons-add.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Custom lock screen: remove the "save logs" button if the error is a "refused on device" error diff --git a/.changeset/olive-ants-clean.md b/.changeset/olive-ants-clean.md deleted file mode 100644 index e7447efeba37..000000000000 --- a/.changeset/olive-ants-clean.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": patch ---- - -Ensure iOS opens links correctly in wallet api webview & remove binancecnt diff --git a/.changeset/perfect-kiwis-tickle.md b/.changeset/perfect-kiwis-tickle.md new file mode 100644 index 000000000000..37abe2eeebd4 --- /dev/null +++ b/.changeset/perfect-kiwis-tickle.md @@ -0,0 +1,6 @@ +--- +"@ledgerhq/hw-transport": patch +"ledger-live-desktop": patch +--- + +fix: fix TransportRaceCondition literal diff --git a/.changeset/perfect-shrimps-type.md b/.changeset/perfect-shrimps-type.md deleted file mode 100644 index c284281a39a4..000000000000 --- a/.changeset/perfect-shrimps-type.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"live-mobile": minor -"@ledgerhq/native-ui": minor ---- - -[LIVE-8347] Add quick actions on the wallet diff --git a/.changeset/plenty-starfishes-train.md b/.changeset/plenty-starfishes-train.md deleted file mode 100644 index 98baf0f7aea2..000000000000 --- a/.changeset/plenty-starfishes-train.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"live-mobile": patch ---- - -fix: wallet-api & platform verify account screen diff --git a/.changeset/pretty-panthers-approve.md b/.changeset/pretty-panthers-approve.md deleted file mode 100644 index ebc8081e5486..000000000000 --- a/.changeset/pretty-panthers-approve.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@ledgerhq/cryptoassets": patch ---- - -Don't use `0` address for evm currencies to avoid gas estimation error in swap when interacting with smart contracts (swapping from token accounts) diff --git a/.changeset/purple-dogs-shake.md b/.changeset/purple-dogs-shake.md new file mode 100644 index 000000000000..4da1e02b0771 --- /dev/null +++ b/.changeset/purple-dogs-shake.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix of OperationDetails view using the wrong currency in the `useNftMetadata` & `useNftCollectionMetadata` hooks diff --git a/.changeset/quick-starfishes-check.md b/.changeset/quick-starfishes-check.md new file mode 100644 index 000000000000..fc7289c65856 --- /dev/null +++ b/.changeset/quick-starfishes-check.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Display troubleshooting usb drawer instead of locked device drawer if stax is unplugged during genuine check diff --git a/.changeset/rare-toes-film.md b/.changeset/rare-toes-film.md new file mode 100644 index 000000000000..194dfc7880e2 --- /dev/null +++ b/.changeset/rare-toes-film.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": patch +--- + +Fix useFeature that was returning a default value instead of null even for unexisting feature flags diff --git a/.changeset/real-wolves-lie.md b/.changeset/real-wolves-lie.md deleted file mode 100644 index 8db0fcb49754..000000000000 --- a/.changeset/real-wolves-lie.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"ledger-live-desktop": patch -"live-mobile": patch ---- - -Conditionally render different text when user arrives at the buy funds modal from a get funds button rather than default of no funds. Applies to mobile and desktop. diff --git a/.changeset/rich-buses-help.md b/.changeset/rich-buses-help.md new file mode 100644 index 000000000000..320113c78ed6 --- /dev/null +++ b/.changeset/rich-buses-help.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix discreet mode on Deposit flow LLM diff --git a/.changeset/nine-kangaroos-lick.md b/.changeset/seven-carrots-join.md similarity index 67% rename from .changeset/nine-kangaroos-lick.md rename to .changeset/seven-carrots-join.md index cd66e77e282b..abea665ec5b4 100644 --- a/.changeset/nine-kangaroos-lick.md +++ b/.changeset/seven-carrots-join.md @@ -4,4 +4,4 @@ "@ledgerhq/live-common": minor --- -feat: send LL version to the manifest-api +Update swap endpoints to v5 on llm and lld diff --git a/.changeset/shaggy-pots-wonder.md b/.changeset/shaggy-pots-wonder.md new file mode 100644 index 000000000000..066008e76d40 --- /dev/null +++ b/.changeset/shaggy-pots-wonder.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +fix scan of ethereum addresses from qr code diff --git a/.changeset/sharp-avocados-turn.md b/.changeset/sharp-avocados-turn.md new file mode 100644 index 000000000000..648b7c4ac094 --- /dev/null +++ b/.changeset/sharp-avocados-turn.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": patch +--- + +Fix WalletAPI fee strategy implementation diff --git a/.changeset/sharp-readers-occur.md b/.changeset/sharp-readers-occur.md new file mode 100644 index 000000000000..a771ebf794d1 --- /dev/null +++ b/.changeset/sharp-readers-occur.md @@ -0,0 +1,6 @@ +--- +"live-mobile": patch +"@ledgerhq/live-common": patch +--- + +add correct drawer when device is locked during pairing diff --git a/.changeset/sharp-wombats-pull.md b/.changeset/sharp-wombats-pull.md new file mode 100644 index 000000000000..5d17006c58f8 --- /dev/null +++ b/.changeset/sharp-wombats-pull.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix onboarding issues when closing quiz drawer diff --git a/.changeset/shiny-apes-rule.md b/.changeset/shiny-apes-rule.md new file mode 100644 index 000000000000..a118b1362759 --- /dev/null +++ b/.changeset/shiny-apes-rule.md @@ -0,0 +1,7 @@ +--- +"@ledgerhq/types-live": patch +"live-mobile": patch +"@ledgerhq/live-common": patch +--- + +Need to add other link firebase for quickAccess Recover diff --git a/.changeset/short-dogs-buy.md b/.changeset/short-dogs-buy.md deleted file mode 100644 index 428984013d17..000000000000 --- a/.changeset/short-dogs-buy.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@ledgerhq/cryptoassets": patch ---- - -Update zcash explorer to zcashblockexplorer.com diff --git a/.changeset/silver-experts-hammer.md b/.changeset/silver-experts-hammer.md new file mode 100644 index 000000000000..1d4df3290bbb --- /dev/null +++ b/.changeset/silver-experts-hammer.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +fix display thumbnail of a story diff --git a/.changeset/lemon-taxis-applaud.md b/.changeset/sixty-carpets-hug.md similarity index 71% rename from .changeset/lemon-taxis-applaud.md rename to .changeset/sixty-carpets-hug.md index 5834cc205afe..7254785e7e35 100644 --- a/.changeset/lemon-taxis-applaud.md +++ b/.changeset/sixty-carpets-hug.md @@ -1,11 +1,11 @@ --- -"@ledgerhq/types-cryptoassets": minor "@ledgerhq/cryptoassets": minor "@ledgerhq/types-live": minor "ledger-live-desktop": minor "live-mobile": minor "@ledgerhq/live-common": minor +"web-tools": minor "@ledgerhq/live-cli": minor --- -Integrate injective + gas rework +Integrate SEI Network diff --git a/.changeset/gentle-tomatoes-draw.md b/.changeset/sixty-cooks-run.md similarity index 55% rename from .changeset/gentle-tomatoes-draw.md rename to .changeset/sixty-cooks-run.md index aab4f0f08eb4..f894e56c3525 100644 --- a/.changeset/gentle-tomatoes-draw.md +++ b/.changeset/sixty-cooks-run.md @@ -2,4 +2,4 @@ "live-mobile": patch --- -Update staking icon +Remove Cardano poolCost diff --git a/.changeset/sixty-horses-joke.md b/.changeset/sixty-horses-joke.md new file mode 100644 index 000000000000..14b3b182a89e --- /dev/null +++ b/.changeset/sixty-horses-joke.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Discover section : Apps Description changed to shortDescription diff --git a/.changeset/sixty-pets-promise.md b/.changeset/sixty-pets-promise.md new file mode 100644 index 000000000000..eb81f1c067b8 --- /dev/null +++ b/.changeset/sixty-pets-promise.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix design of bluetooth pairing error screen diff --git a/.changeset/small-jars-hug.md b/.changeset/small-jars-hug.md deleted file mode 100644 index ef29076e9916..000000000000 --- a/.changeset/small-jars-hug.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@ledgerhq/cryptoassets": major -"ledger-live-desktop": minor -"live-mobile": minor -"@ledgerhq/live-common": major -"@ledgerhq/types-cryptoassets": minor -"@ledgerhq/coin-framework": minor -"@ledgerhq/coin-evm": minor -"@ledgerhq/live-cli": minor -"@ledgerhq/live-env": minor ---- - -Migrate Ethereum family implementation to EVM family - -Replace the legcay Ethereum familly implementation that was present in ledger-live-common by the coin-evm lib implementation. -This change was made in order to improve scalabillity and maintainability of the evm coins, as well as more easilly integrate new evm based chains in the future. diff --git a/.changeset/small-singers-melt.md b/.changeset/small-singers-melt.md new file mode 100644 index 000000000000..cd90854f94ca --- /dev/null +++ b/.changeset/small-singers-melt.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Fix translation text diff --git a/.changeset/smart-candles-lie.md b/.changeset/smart-candles-lie.md new file mode 100644 index 000000000000..6c1971b8e0a9 --- /dev/null +++ b/.changeset/smart-candles-lie.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix wrong fee value for evm custom fee in strategies list diff --git a/.changeset/soft-foxes-suffer.md b/.changeset/soft-foxes-suffer.md new file mode 100644 index 000000000000..a0a9437ef602 --- /dev/null +++ b/.changeset/soft-foxes-suffer.md @@ -0,0 +1,7 @@ +--- +"ledger-live-desktop": minor +"live-mobile": minor +"@ledgerhq/live-common": minor +--- + +feat(wallet-api): add custom handler support diff --git a/.changeset/sour-melons-exercise.md b/.changeset/sour-melons-exercise.md new file mode 100644 index 000000000000..d8b000aabedd --- /dev/null +++ b/.changeset/sour-melons-exercise.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Fix drawers in LLM onboarding diff --git a/.changeset/sour-shrimps-build.md b/.changeset/sour-shrimps-build.md new file mode 100644 index 000000000000..e871d967360c --- /dev/null +++ b/.changeset/sour-shrimps-build.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Update copy instruction when exporting accounts diff --git a/.changeset/strong-flowers-draw.md b/.changeset/strong-flowers-draw.md new file mode 100644 index 000000000000..28172e3ef16d --- /dev/null +++ b/.changeset/strong-flowers-draw.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Update UI in Manager for Services Recover diff --git a/.changeset/sweet-experts-collect.md b/.changeset/sweet-experts-collect.md new file mode 100644 index 000000000000..792b7cee40bc --- /dev/null +++ b/.changeset/sweet-experts-collect.md @@ -0,0 +1,5 @@ +--- +"@ledgerhq/live-common": minor +--- + +Add default blockHeight to Stellar account diff --git a/.changeset/tall-penguins-deliver.md b/.changeset/tall-penguins-deliver.md new file mode 100644 index 000000000000..75fe42664c70 --- /dev/null +++ b/.changeset/tall-penguins-deliver.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Align NotEnoughGas error in LLD and LLM diff --git a/.changeset/thick-cars-compete.md b/.changeset/thick-cars-compete.md new file mode 100644 index 000000000000..b8fcd334cd1a --- /dev/null +++ b/.changeset/thick-cars-compete.md @@ -0,0 +1,6 @@ +--- +"@ledgerhq/cryptoassets": patch +"ledger-libs": patch +--- + +remove tokens definition for ICP chain diff --git a/.changeset/thin-news-double.md b/.changeset/thin-news-double.md new file mode 100644 index 000000000000..60015b706b09 --- /dev/null +++ b/.changeset/thin-news-double.md @@ -0,0 +1,5 @@ +--- +"live-mobile": patch +--- + +Create new bluetooth pairing flow screen for onboarding diff --git a/.changeset/twelve-starfishes-joke.md b/.changeset/twelve-starfishes-joke.md new file mode 100644 index 000000000000..8a66841f7b89 --- /dev/null +++ b/.changeset/twelve-starfishes-joke.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +Add a new drawer view to ask user before cancelling current firmware update diff --git a/.changeset/twenty-bats-boil.md b/.changeset/twenty-bats-boil.md new file mode 100644 index 000000000000..244141cdd5c2 --- /dev/null +++ b/.changeset/twenty-bats-boil.md @@ -0,0 +1,8 @@ +--- +"@ledgerhq/errors": minor +"ledger-live-desktop": minor +"live-mobile": minor +"@ledgerhq/live-common": minor +--- + +Change network error to better suit node flakiness diff --git a/.changeset/twenty-ears-care.md b/.changeset/twenty-ears-care.md deleted file mode 100644 index d5d82a373944..000000000000 --- a/.changeset/twenty-ears-care.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"ledger-live-desktop": patch -"live-mobile": patch ---- - -Fix jest config to generate coverage report and include untested files diff --git a/.changeset/unlucky-cups-hunt.md b/.changeset/unlucky-cups-hunt.md new file mode 100644 index 000000000000..c261baad12b4 --- /dev/null +++ b/.changeset/unlucky-cups-hunt.md @@ -0,0 +1,5 @@ +--- +"ledger-live-desktop": patch +--- + +on previous cta recover onboarding, the app redirect to disclaimer screen diff --git a/.changeset/witty-pigs-beam.md b/.changeset/witty-pigs-beam.md new file mode 100644 index 000000000000..d6a6724f84bd --- /dev/null +++ b/.changeset/witty-pigs-beam.md @@ -0,0 +1,12 @@ +--- +"ledger-live-desktop": patch +"live-mobile": patch +--- + +fix NotEnoughGas related UI on LLM and LLD + +- fix buy CTA button style on LLD to make it more visible +- add related support link for NotEnoughGas error on LLM and LLD to display an "learn more" CTA redirecting to [related CS article](https://support.ledger.com/hc/en-us/articles/9096370252573?support=true) +- fix buy button when NotEnoughGas on LLM + - The logic to display the button was related to the currency being sent and not the main account currency (if I don't have enough fund to pay for the gas when I want to send USDT on ethereum, I need to buy some ETH and not some USDT) + - The related text was wrongly hardcoded only for ethereum currency when a user might be using another evm network and thus needing to buy a different currency than ethereum (i.e: the currency of the actual EVM network he is using) diff --git a/.changeset/quick-students-glow.md b/.changeset/yellow-sloths-pay.md similarity index 56% rename from .changeset/quick-students-glow.md rename to .changeset/yellow-sloths-pay.md index 32dd11f1a4f4..ef4f05de64c4 100644 --- a/.changeset/quick-students-glow.md +++ b/.changeset/yellow-sloths-pay.md @@ -4,4 +4,4 @@ "@ledgerhq/live-common": patch --- -Update multibuy manifest to v2 to ensure full backwards compatibility +Add 'Ledger By Kiln' in the list of Tezos bakers diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index ea7766fdeffe..cb49640e7572 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -10,8 +10,8 @@ _Replace this text by a clear and concise description of what this pull request ### ❓ Context -- **Impacted projects**: `` -- **Linked resource(s)**: `` +- **Impacted projects**: `` +- **Linked resource(s)**: [] ### ✅ Checklist diff --git a/.github/workflows/backup/version-or-release.yml b/.github/workflows/backup/version-or-release.yml index 0d0d2c2e62d1..a5f31b722917 100644 --- a/.github/workflows/backup/version-or-release.yml +++ b/.github/workflows/backup/version-or-release.yml @@ -19,9 +19,9 @@ jobs: uses: ./tools/actions/composites/setup-toolchain - uses: ruby/setup-ruby@v1 with: - ruby-version: - 3.1.2 # Not needed with a .ruby-version file - # runs 'bundle install' and caches installed gems automatically + ruby-version: 3.2.2 + # Not needed with a .ruby-version file + # runs 'bundle install' and caches installed gems automatically - name: Install Dependencies run: pnpm i -F "ledger-live" -F "{libs/**}..." -F "@ledgerhq/live-cli" - name: Create Release Pull Request or Publish to npm/Github diff --git a/.github/workflows/bot-portfolio-report.yml b/.github/workflows/bot-portfolio-report.yml index 2632b6b4d600..a720cea03172 100644 --- a/.github/workflows/bot-portfolio-report.yml +++ b/.github/workflows/bot-portfolio-report.yml @@ -38,6 +38,9 @@ jobs: path: coin-apps - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: install and build run: | pnpm i --filter="live-cli..." --filter="ledger-live" diff --git a/.github/workflows/bot-super-report-custom.yml b/.github/workflows/bot-super-report-custom.yml index b48b9fd8c050..d2c84618913f 100644 --- a/.github/workflows/bot-super-report-custom.yml +++ b/.github/workflows/bot-super-report-custom.yml @@ -18,6 +18,9 @@ jobs: - uses: actions/checkout@v3 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install dependencies run: pnpm i --filter='!./apps/**' diff --git a/.github/workflows/bot-super-report.yml b/.github/workflows/bot-super-report.yml index ec1453165e6f..c4ae3d773256 100644 --- a/.github/workflows/bot-super-report.yml +++ b/.github/workflows/bot-super-report.yml @@ -10,6 +10,9 @@ jobs: - uses: actions/checkout@v3 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install dependencies run: pnpm i --filter='!./apps/**' diff --git a/.github/workflows/bot-transfer.yml b/.github/workflows/bot-transfer.yml index e782eeaaaf6d..e32e8afc7b83 100644 --- a/.github/workflows/bot-transfer.yml +++ b/.github/workflows/bot-transfer.yml @@ -39,6 +39,9 @@ jobs: path: coin-apps - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: pull docker image run: docker pull ghcr.io/ledgerhq/speculos - name: install and build diff --git a/.github/workflows/build-desktop.yml b/.github/workflows/build-desktop.yml index 19d50dd33af3..e534843a42f5 100644 --- a/.github/workflows/build-desktop.yml +++ b/.github/workflows/build-desktop.yml @@ -45,6 +45,9 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-build-desktop id: build-desktop with: @@ -61,7 +64,7 @@ jobs: build-desktop-app-windows: name: "Build Ledger Live Desktop (Windows)" - runs-on: [ledger-live-4xlarge-windows-2022] + runs-on: [windows-latest] env: NODE_OPTIONS: "--max-old-space-size=7168" steps: @@ -77,6 +80,8 @@ jobs: uses: ./tools/actions/composites/setup-toolchain with: install_dotnet: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-build-desktop id: build-desktop with: @@ -95,7 +100,7 @@ jobs: build-desktop-app-macos: name: "Build Ledger Live Desktop (Mac OS X)" - runs-on: [m1, ARM64] + runs-on: [macos-latest] env: NODE_OPTIONS: "--max-old-space-size=7168" steps: @@ -111,7 +116,8 @@ jobs: - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain with: - pnpm_dest: ${{ runner.temp }}/setup-pnpm + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-build-desktop id: build-desktop with: diff --git a/.github/workflows/build-mobile.yml b/.github/workflows/build-mobile.yml index f31db6431494..1e9508cf147b 100644 --- a/.github/workflows/build-mobile.yml +++ b/.github/workflows/build-mobile.yml @@ -41,9 +41,12 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.1.2 + ruby-version: 3.2.2 env: ImageOS: ubuntu20 - uses: actions/setup-java@v3 @@ -111,9 +114,12 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.1.2 + ruby-version: 3.2.2 - name: Cache LLM pods uses: actions/cache@v3 with: diff --git a/.github/workflows/cal-importer-stg.yml b/.github/workflows/cal-importer-stg.yml index f863f36e2907..8996f5c53172 100644 --- a/.github/workflows/cal-importer-stg.yml +++ b/.github/workflows/cal-importer-stg.yml @@ -19,6 +19,9 @@ jobs: path: crypto-assets - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: install and build continue-on-error: true run: | diff --git a/.github/workflows/cal-importer.yml b/.github/workflows/cal-importer.yml index d4814ed0214a..484fb059d8ac 100644 --- a/.github/workflows/cal-importer.yml +++ b/.github/workflows/cal-importer.yml @@ -19,6 +19,9 @@ jobs: path: crypto-assets - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: install and build continue-on-error: true run: | diff --git a/.github/workflows/commitlint.yml b/.github/workflows/commitlint.yml index 546465aa8872..5c218775ca3d 100644 --- a/.github/workflows/commitlint.yml +++ b/.github/workflows/commitlint.yml @@ -29,6 +29,9 @@ jobs: fetch-depth: 0 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install dependencies run: pnpm i --filter="ledger-live" - name: Lint commits diff --git a/.github/workflows/generate-screenshots.yml b/.github/workflows/generate-screenshots.yml index 0a09147bdf1a..c62e654e2c6a 100644 --- a/.github/workflows/generate-screenshots.yml +++ b/.github/workflows/generate-screenshots.yml @@ -64,6 +64,11 @@ jobs: run: | git config user.email "105061298+live-github-bot[bot]@users.noreply.github.com" git config user.name "live-github-bot[bot]" + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: @@ -106,13 +111,17 @@ jobs: run: gh pr checkout ${{ inputs.number }} env: GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + upgrade_npm: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: - skip_python: true skip_ruby: true install_playwright: true - upgrade_npm: true aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: set git user @@ -153,13 +162,17 @@ jobs: run: gh pr checkout ${{ inputs.number }} env: GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + no_pnpm_cache: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: - skip_python: true skip_ruby: true install_playwright: true - pnpm_dest: ${{ runner.temp }}/setup-pnpm aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: set git user diff --git a/.github/workflows/healthchecks-runners.yaml b/.github/workflows/healthchecks-runners.yaml index e385d4081ae1..1dca01622c00 100644 --- a/.github/workflows/healthchecks-runners.yaml +++ b/.github/workflows/healthchecks-runners.yaml @@ -33,7 +33,7 @@ jobs: - uses: pnpm/action-setup@v2 if: always() with: - version: 8.7 + version: 8.8 dest: ${{ runner.temp }}/setup-pnpm - uses: actions/setup-node@v3 if: always() @@ -42,7 +42,7 @@ jobs: - uses: ruby/setup-ruby@v1 if: always() with: - ruby-version: 3.1.2 + ruby-version: 3.2.2 env: ImageOS: ubuntu20 - uses: actions/setup-java@v3 @@ -158,7 +158,7 @@ jobs: - uses: pnpm/action-setup@v2 if: always() with: - version: 8.7 + version: 8.8 dest: ${{ runner.temp }}/setup-pnpm - uses: actions/setup-node@v3 if: always() @@ -232,7 +232,7 @@ jobs: - uses: pnpm/action-setup@v2 if: always() with: - version: 8.7 + version: 8.8 dest: ${{ runner.temp }}/setup-pnpm - uses: actions/setup-node@v3 if: always() @@ -241,7 +241,7 @@ jobs: # - uses: ruby/setup-ruby@v1 # if: always() # with: - # ruby-version: 3.1.2 + # ruby-version: 3.2.2 # env: # ImageOS: macos11 - name: check pnpm diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index f26c8c942491..f646279d31a2 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -11,13 +11,19 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: + - name: generate token + id: generate-token + uses: tibdex/github-app-token@v1 + with: + app_id: ${{ secrets.GH_BOT_APP_ID }} + private_key: ${{ secrets.GH_BOT_PRIVATE_KEY }} - uses: actions/labeler@v4 with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + repo-token: ${{ steps.generate-token.outputs.token }} - uses: actions/github-script@v6 if: github.event.pull_request.head.repo.fork with: - github-token: ${{ secrets.GITHUB_TOKEN }} + github-token: ${{ steps.generate-token.outputs.token }} script: | try { const { data: rawLabels } = await github.rest.issues.listLabelsOnIssue({ diff --git a/.github/workflows/regen-doc.yml b/.github/workflows/regen-doc.yml index 370faea60acc..316a4bdc785f 100644 --- a/.github/workflows/regen-doc.yml +++ b/.github/workflows/regen-doc.yml @@ -52,6 +52,9 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install dependencies run: pnpm i --filter="!./apps/**" - name: run doc diff --git a/.github/workflows/regen-pods.yml b/.github/workflows/regen-pods.yml index bd52952ef4c8..880604e3bd40 100644 --- a/.github/workflows/regen-pods.yml +++ b/.github/workflows/regen-pods.yml @@ -55,9 +55,12 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ruby/setup-ruby@v1 with: - ruby-version: 3.1.2 + ruby-version: 3.2.2 - name: Cache LLM pods uses: actions/cache@v3 with: diff --git a/.github/workflows/release-create.yml b/.github/workflows/release-create.yml index 9cde165e4e12..e54a6dd5d2d3 100644 --- a/.github/workflows/release-create.yml +++ b/.github/workflows/release-create.yml @@ -9,6 +9,12 @@ jobs: env: NODE_OPTIONS: "--max-old-space-size=7168" steps: + - uses: dorny/paths-filter@v2 + id: filters + with: + filters: | + cryptoassets: + - 'libs/ledgerjs/packages/cryptoassets/src/data/**' - name: generate token id: generate-token uses: tibdex/github-app-token@v1 @@ -30,6 +36,13 @@ jobs: uses: ./tools/actions/composites/setup-toolchain - name: install dependencies run: pnpm i -F "ledger-live" + - name: update dynamic call tokens + run: pnpm import:cal_tokens + - name: commit new cryptoassets + if: steps.filters.outputs.cryptoassets == 'true' + run: | + git add . + git commit -m "chore(prerelease) update cryptoassets list - name: enter prerelease mode run: pnpm changeset pre enter next - name: commit diff --git a/.github/workflows/release-final-nightly.yml b/.github/workflows/release-final-nightly.yml index 7296fea6cb71..e541498d2137 100644 --- a/.github/workflows/release-final-nightly.yml +++ b/.github/workflows/release-final-nightly.yml @@ -35,9 +35,9 @@ jobs: uses: ./tools/actions/composites/setup-toolchain - uses: ruby/setup-ruby@v1 with: - ruby-version: - 3.1.2 # Not needed with a .ruby-version file - # runs 'bundle install' and caches installed gems automatically + ruby-version: 3.2.2 + # Not needed with a .ruby-version file + # runs 'bundle install' and caches installed gems automatically - uses: ./tools/actions/get-package-infos id: desktop-version with: diff --git a/.github/workflows/release-final.yml b/.github/workflows/release-final.yml index d0da01d83295..795c5844fef1 100644 --- a/.github/workflows/release-final.yml +++ b/.github/workflows/release-final.yml @@ -44,17 +44,17 @@ jobs: git config user.name "live-github-bot[bot]" - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain - # - uses: ruby/setup-ruby@v1 - # with: - # ruby-version: 3.1.2 - # - name: Cache LLM pods - # uses: actions/cache@v3 - # with: - # path: | - # apps/ledger-live-mobile/ios/Pods - # ~/Library/Caches/CocoaPods - # ~/.cocoapods - # key: ${{ runner.os }}-pods-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock') }} + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2.2 + - name: Cache LLM pods + uses: actions/cache@v3 + with: + path: | + apps/ledger-live-mobile/ios/Pods + ~/Library/Caches/CocoaPods + ~/.cocoapods + key: ${{ runner.os }}-pods-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock') }} - name: install dependencies run: pnpm i -F "ledger-live" -F "{libs/**}..." -F "@ledgerhq/live-cli" - name: build libs diff --git a/.github/workflows/renovate.yml b/.github/workflows/renovate.yml index 301774e17a5c..1099351699d3 100644 --- a/.github/workflows/renovate.yml +++ b/.github/workflows/renovate.yml @@ -4,7 +4,7 @@ on: schedule: # The "*" (#42, asterisk) character has special semantics in YAML, so this # string has to be quoted. - - cron: "0/30 * * * *" + - cron: "* 22 * * 1-5" workflow_dispatch: jobs: diff --git a/.github/workflows/test-desktop-external.yml b/.github/workflows/test-desktop-external.yml index 4e6c7a785476..78d7f367042f 100644 --- a/.github/workflows/test-desktop-external.yml +++ b/.github/workflows/test-desktop-external.yml @@ -35,11 +35,14 @@ jobs: with: ref: ${{ github.ref_name }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + install_dotnet: true - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: skip_builds: true - install_dotnet: true - name: lint run: | pnpm lint --filter="ledger-live-desktop" --api="http://127.0.0.1:${{ steps.turborepo-cache-server.outputs.port }}" --token="yolo" --team="foo" -- --format="json" -o="lint.json" @@ -67,6 +70,8 @@ jobs: with: ref: ${{ github.ref_name }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: @@ -87,6 +92,10 @@ jobs: with: ref: ${{ github.ref_name }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + install_dotnet: true - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: @@ -111,24 +120,31 @@ jobs: with: ref: ${{ github.ref_name }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + install_dotnet: true - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: - skip_python: true skip_ruby: true install_playwright: true - name: Run playwright tests [Linux => xvfb-run] id: tests run: | xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- pnpm desktop test:playwright:smoke - - name: upload diffs to imgur + - name: upload diffs to s3 if: always() && !cancelled() uses: ./tools/actions/upload-images - id: imgur + id: s3 with: path: apps/ledger-live-desktop/tests/artifacts/test-results workspace: ${{ github.workspace }} os: linux + group-name: ${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_number }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_SCREENSHOTS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SCREENSHOTS_SECRET_ACCESS_KEY }} - name: upload ci suggested screenshots if: always() && !cancelled() uses: actions/upload-artifact@v3 diff --git a/.github/workflows/test-desktop.yml b/.github/workflows/test-desktop.yml index 5345c8b9b825..88015d9cc279 100644 --- a/.github/workflows/test-desktop.yml +++ b/.github/workflows/test-desktop.yml @@ -23,18 +23,12 @@ on: description: true if the PR is in draft required: false default: "false" - full-tests: - description: Set to true to run the full e2e tests - required: false - type: boolean - default: false concurrency: group: ${{ github.workflow }}-${{ github.ref_name != 'develop' && github.ref || github.run_id }} cancel-in-progress: true env: - RUN_FULL_SUITE: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.full-tests) }} REFNAME: ${{ (github.event_name == 'workflow_dispatch' && (inputs.ref || github.ref_name)) || github.sha }} jobs: @@ -50,11 +44,16 @@ jobs: with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + install_dotnet: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: skip_builds: true - install_dotnet: true aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: lint @@ -84,6 +83,11 @@ jobs: with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: @@ -106,6 +110,11 @@ jobs: with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: @@ -127,22 +136,23 @@ jobs: # DEBUG: "pw:browser*" # DEBUG_LOGS: 1 runs-on: [ledger-live-4xlarge-windows-2022] - if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.full-tests) }} steps: - uses: LedgerHQ/ledger-live/tools/actions/composites/checkout-merge@develop with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} - - uses: actions/setup-dotnet@v2 + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain with: - dotnet-version: 2.1.816 + upgrade_npm: true + install_dotnet: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: install_node_gyp: true install_playwright: true - upgrade_npm: true - install_dotnet: true aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Run playwright tests @@ -150,26 +160,24 @@ jobs: run: | pnpm desktop test:playwright shell: bash - - name: upload diffs to imgur + - name: upload diffs to s3 if: always() && !cancelled() uses: ./tools/actions/upload-images - id: imgur + id: s3 with: path: apps/ledger-live-desktop/tests/artifacts/test-results workspace: ${{ github.workspace }} os: windows + group-name: ${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_number }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_SCREENSHOTS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SCREENSHOTS_SECRET_ACCESS_KEY }} - name: upload ci suggested screenshots if: always() && !cancelled() uses: actions/upload-artifact@v3 with: name: images path: images-windows.json - - name: upload network responses - if: always() - uses: actions/upload-artifact@v3 - with: - name: windows-network-responses - path: apps/ledger-live-desktop/tests/artifacts/networkResponses.log - name: Upload playwright test results [On Failure] uses: actions/upload-artifact@v3 if: failure() && !cancelled() @@ -181,6 +189,7 @@ jobs: apps/ledger-live-desktop/tests/artifacts/coverage apps/ledger-live-desktop/tests/artifacts/videos apps/ledger-live-desktop/tests/artifacts/logs + apps/ledger-live-desktop/tests/artifacts/*.log - name: Upload Allure Report if: always() uses: actions/upload-artifact@v3 @@ -206,10 +215,14 @@ jobs: with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: - skip_python: true skip_ruby: true install_playwright: true aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} @@ -217,31 +230,25 @@ jobs: - name: Run playwright tests [Linux => xvfb-run] id: tests run: | - if [[ $RUN_FULL_SUITE == true ]]; then - xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- pnpm desktop test:playwright - else - xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- pnpm desktop test:playwright:smoke - fi - - name: upload diffs to imgur + xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- pnpm desktop test:playwright + - name: upload diffs to s3 if: always() && !cancelled() uses: ./tools/actions/upload-images - id: imgur + id: s3 with: path: apps/ledger-live-desktop/tests/artifacts/test-results workspace: ${{ github.workspace }} os: linux + group-name: ${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_number }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_SCREENSHOTS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SCREENSHOTS_SECRET_ACCESS_KEY }} - name: upload ci suggested screenshots if: always() && !cancelled() uses: actions/upload-artifact@v3 with: name: images path: images-linux.json - - name: upload network responses - if: always() - uses: actions/upload-artifact@v3 - with: - name: linux-network-responses - path: apps/ledger-live-desktop/tests/artifacts/networkResponses.log - name: Upload playwright test results [On Failure] uses: actions/upload-artifact@v3 if: failure() && !cancelled() @@ -253,6 +260,7 @@ jobs: apps/ledger-live-desktop/tests/artifacts/coverage apps/ledger-live-desktop/tests/artifacts/videos apps/ledger-live-desktop/tests/artifacts/logs + apps/ledger-live-desktop/tests/artifacts/*.log - name: Upload Allure Report if: always() uses: actions/upload-artifact@v3 @@ -272,45 +280,46 @@ jobs: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 # DEBUG: "pw:browser*" # DEBUG_LOGS: 1 - if: ${{ github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.full-tests) }} steps: - uses: LedgerHQ/ledger-live/tools/actions/composites/checkout-merge@develop with: ref: ${{ env.REFNAME }} base: ${{ inputs.base_ref }} + - name: Setup the toolchain + uses: ./tools/actions/composites/setup-toolchain + with: + no_pnpm_cache: true + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ./tools/actions/composites/setup-test-desktop id: setup-test-desktop with: - skip_python: true skip_ruby: true install_playwright: true - pnpm_dest: ${{ runner.temp }}/setup-pnpm aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Run playwright tests id: tests run: | pnpm desktop test:playwright - - name: upload diffs to imgur + - name: upload diffs to s3 if: always() && !cancelled() uses: ./tools/actions/upload-images - id: imgur + id: s3 with: path: apps/ledger-live-desktop/tests/artifacts/test-results workspace: ${{ github.workspace }} os: macos + group-name: ${{ github.ref_name }}-${{ github.run_id }}-${{ github.run_number }} + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_S3_SCREENSHOTS_ACCESS_KEY }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SCREENSHOTS_SECRET_ACCESS_KEY }} - name: upload ci suggested screenshots if: always() && !cancelled() uses: actions/upload-artifact@v3 with: name: images path: images-macos.json - - name: upload network responses - if: always() - uses: actions/upload-artifact@v3 - with: - name: macos-network-responses - path: apps/ledger-live-desktop/tests/artifacts/networkResponses.log - name: Upload playwright test results [On Failure] uses: actions/upload-artifact@v3 if: failure() && !cancelled() @@ -322,6 +331,7 @@ jobs: apps/ledger-live-desktop/tests/artifacts/coverage apps/ledger-live-desktop/tests/artifacts/videos apps/ledger-live-desktop/tests/artifacts/logs + apps/ledger-live-desktop/tests/artifacts/*.log - name: Upload Allure Report if: always() uses: actions/upload-artifact@v3 @@ -352,7 +362,7 @@ jobs: with: script: | const fs = require("fs"); - const files = ${{ env.RUN_FULL_SUITE }} ? ["images-linux", "images-windows", "images-macos"] : ["images-linux"] + const files = ["images-linux", "images-windows", "images-macos"]; let result = {}; for (const file of files) { try { @@ -422,7 +432,7 @@ jobs: pass: ${{ needs.deadcodecheck.result == 'success' }}, }; - const report = ${{ env.RUN_FULL_SUITE }} ? { + const report = { mac: { pass: ${{ needs.e2e-tests-mac.outputs.status == 'success' }}, status: "${{ needs.e2e-tests-mac.outputs.status }}", @@ -435,11 +445,6 @@ jobs: pass: ${{ needs.e2e-tests-windows.outputs.status == 'success' }}, status: "${{ needs.e2e-tests-windows.outputs.status }}", }, - } : { - linux: { - pass: ${{ needs.e2e-tests-linux.outputs.status == 'success' }}, - status: "${{ needs.e2e-tests-linux.outputs.status }}", - }, }; let summary = `### TypeCheck @@ -579,20 +584,11 @@ jobs: } }, { - ...(${{ env.RUN_FULL_SUITE }} ? { - "type": "section", - "text": { - "type": "mrkdwn", - "text": `- 🐧 linux: ${report.linux.pass ? "✅" : "❌"}\n - 🪟 windows: ${report.windows.pass ? "✅" : "❌"}\n - 🍏 macos: ${report.mac.pass ? "✅" : "❌"}\n` - } - } : - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": `- 🐧 linux: ${report.linux.pass ? "✅" : "❌"}\n` - } - }) + "type": "section", + "text": { + "type": "mrkdwn", + "text": `- 🐧 linux: ${report.linux.pass ? "✅" : "❌"}\n - 🪟 windows: ${report.windows.pass ? "✅" : "❌"}\n - 🍏 macos: ${report.mac.pass ? "✅" : "❌"}\n` + } }, { "type": "divider" diff --git a/.github/workflows/test-integration-pr.yml b/.github/workflows/test-integration-pr.yml index 8f7beb5c62bc..3d039b0a5572 100644 --- a/.github/workflows/test-integration-pr.yml +++ b/.github/workflows/test-integration-pr.yml @@ -55,6 +55,8 @@ jobs: uses: ./tools/actions/composites/setup-toolchain with: upgrade_npm: ${{ matrix.os == 'windows-latest' }} + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install node-gyp globally if: runner.os == 'Windows' run: | diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index 5110b394ef08..89b010c61ed2 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -41,6 +41,8 @@ jobs: uses: ./tools/actions/composites/setup-toolchain with: upgrade_npm: ${{ matrix.os == 'windows-latest' }} + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install node-gyp globally if: runner.os == 'Windows' run: | diff --git a/.github/workflows/test-mobile-e2e.yml b/.github/workflows/test-mobile-e2e.yml index 0d2220ca6750..e50fd0501380 100644 --- a/.github/workflows/test-mobile-e2e.yml +++ b/.github/workflows/test-mobile-e2e.yml @@ -48,7 +48,8 @@ jobs: - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain with: - pnpm_dest: ${{ runner.temp }}/setup-pnpm + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install applesimutils run: | brew update @@ -62,6 +63,21 @@ jobs: ~/Library/Caches/CocoaPods ~/.cocoapods key: ${{ runner.os }}-pods-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock') }} + + - name: cache detox build + uses: tespkg/actions-cache@v1 + id: detox-build + with: + path: ${{ github.workspace }}/apps/ledger-live-mobile/ios/build/Build/Products/Release-iphonesimulator + key: ${{ runner.os }}-detox-${{ hashFiles('apps/ledger-live-mobile/ios/Podfile.lock', 'apps/ledger-live-mobile/ios/ledgerlivemobile.xcodeproj/project.pbxproj') }} + restore-keys: | + ${{ runner.os }}-detox- + accessKey: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + secretKey: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} + bucket: ll-gha-s3-cache + region: eu-west-1 + use-fallback: false + - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache @@ -86,8 +102,18 @@ jobs: ID=$(xcrun simctl create "iPhone 13" "iPhone 13") echo "id=$ID" >> $GITHUB_OUTPUT - name: Build iOS app for Detox test run + if: steps.detox-build.outputs.cache-hit != 'true' run: | pnpm mobile e2e:build -c ios.sim.release + + - name: Build JS Bundle app for Detox test run + if: steps.detox-build.outputs.cache-hit == 'true' + run: | + pnpm mobile bundle:ios + pnpm mobile exec detox clean-framework-cache + pnpm mobile exec detox build-framework-cache + cd apps/ledger-live-mobile + mv main.jsbundle ios/build/Build/Products/Release-iphonesimulator/main.jsbundle - name: Test iOS app id: detox run: | @@ -140,7 +166,10 @@ jobs: with: ref: ${{ (github.event_name == 'workflow_dispatch' && (inputs.ref || github.ref_name)) || github.sha }} - name: Setup the toolchain - uses: LedgerHQ/ledger-live/tools/actions/composites/setup-toolchain@develop + uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: setup JDK 11 uses: actions/setup-java@v3 with: @@ -404,3 +433,11 @@ jobs: payload-file-path: "./payload-slack-content.json" env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} + - name: post to a Slack channel + if: contains(fromJson('["develop", "main"]'), github.ref_name) + uses: slackapi/slack-github-action@v1.23.0 + with: + channel-id: "C05FKJ7DFAP" + payload-file-path: "./payload-slack-content.json" + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_USER_OAUTH_ACCESS_TOKEN }} diff --git a/.github/workflows/test-mobile.yml b/.github/workflows/test-mobile.yml index 83bd8c198107..8a0524712f46 100644 --- a/.github/workflows/test-mobile.yml +++ b/.github/workflows/test-mobile.yml @@ -38,9 +38,12 @@ jobs: base: ${{ inputs.base_ref }} - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7 + ruby-version: 3.2.2 - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cab601c0f6f7..091da9897aae 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -37,6 +37,9 @@ jobs: base: ${{ inputs.since_branch }} - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: Install dependencies run: pnpm i --filter="!./apps/**" - name: run doc @@ -61,6 +64,9 @@ jobs: base: ${{ inputs.since_branch }} - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache @@ -90,6 +96,9 @@ jobs: base: ${{ inputs.since_branch }} - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache @@ -132,12 +141,9 @@ jobs: fetch-depth: 0 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain - # - uses: actions/setup-python@v4 - # with: - # python-version: "3.10" - # - uses: ruby/setup-ruby@v1 - # with: - # ruby-version: 2.6 + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache @@ -195,13 +201,13 @@ jobs: fetch-depth: 0 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain - # - uses: actions/setup-python@v4 - # with: - # python-version: "3.10" + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - uses: ruby/setup-ruby@v1 if: ${{ matrix.os == 'macos-latest' }} with: - ruby-version: 2.6 + ruby-version: 3.2.2 - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache @@ -252,12 +258,9 @@ jobs: fetch-depth: 0 - name: Setup the toolchain uses: ./tools/actions/composites/setup-toolchain - # - uses: actions/setup-python@v4 - # with: - # python-version: "3.10" - # - uses: ruby/setup-ruby@v1 - # with: - # ruby-version: 2.6 + with: + aws-access-key: ${{ secrets.AWS_S3_CACHE_ACCESS_KEY }} + aws-secret-key: ${{ secrets.AWS_S3_CACHE_SECRET_KEY }} - name: TurboRepo local caching server id: turborepo-cache-server uses: ./tools/actions/turborepo-s3-cache diff --git a/.pnpmfile.cjs b/.pnpmfile.cjs index d3637aad555c..578ed60c8d37 100644 --- a/.pnpmfile.cjs +++ b/.pnpmfile.cjs @@ -85,7 +85,7 @@ function readPackage(pkg, context) { }), /* React Native and Metro bundler packages */ // Crashes ios build if removed /!\ - addDependencies("react-native-codegen", { + addDependencies("@react-native/codegen", { glob: "*", invariant: "*", }), @@ -94,9 +94,13 @@ function readPackage(pkg, context) { mkdirp: "*", yargs: "*", }), + addPeerDependencies("@react-native-community/cli", { "metro-resolver": "*", }), + addPeerDependencies("@react-native-community/cli-tools", { + "find-up": "*", + }), addPeerDependencies("metro-config", { "metro-transform-worker": "*", }), @@ -136,6 +140,8 @@ function readPackage(pkg, context) { addPeerDependencies("expo", { "react-native": "*", react: "*", + "expo-modules-autolinking": "*", + "expo-modules-core": "*", }), addPeerDependencies(/^expo-/, { "expo-modules-core": "*", @@ -144,6 +150,7 @@ function readPackage(pkg, context) { react: "*", }), addPeerDependencies("expo-asset", { + "expo-modules-core": "*", "expo-file-system": "*", }), addPeerDependencies("expo-font", { diff --git a/.prototools b/.prototools index 0ced5872f727..9a3197555d71 100644 --- a/.prototools +++ b/.prototools @@ -1,3 +1,3 @@ -node = "18.17.1" +node = "18.18.0" npm = "9.8.1" -pnpm = "8.7.0" +pnpm = "8.8.0" diff --git a/apps/cli/CHANGELOG.md b/apps/cli/CHANGELOG.md index b9263e62378c..b06fcff1d634 100644 --- a/apps/cli/CHANGELOG.md +++ b/apps/cli/CHANGELOG.md @@ -1,5 +1,45 @@ # @ledgerhq/live-cli +## 22.13.0 + +### Minor Changes + +- [#4583](https://github.com/LedgerHQ/ledger-live/pull/4583) [`f527d1bb5a`](https://github.com/LedgerHQ/ledger-live/commit/f527d1bb5a2888a916f761d43d2ba5093eaa3e3f) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Integrate injective + gas rework + +- [#4285](https://github.com/LedgerHQ/ledger-live/pull/4285) [`533278e2c4`](https://github.com/LedgerHQ/ledger-live/commit/533278e2c40ee764ecb87d4430fa6650f251ff0c) Thanks [@chabroA](https://github.com/chabroA)! - Migrate Ethereum family implementation to EVM family + + Replace the legcay Ethereum familly implementation that was present in ledger-live-common by the coin-evm lib implementation. + This change was made in order to improve scalabillity and maintainability of the evm coins, as well as more easilly integrate new evm based chains in the future. + +### Patch Changes + +- Updated dependencies [[`51857f5c20`](https://github.com/LedgerHQ/ledger-live/commit/51857f5c2016d435fa970fac899aa906e3f97722), [`61a891b06f`](https://github.com/LedgerHQ/ledger-live/commit/61a891b06f9028f285f87c321487f691272a9172), [`72288402ec`](https://github.com/LedgerHQ/ledger-live/commit/72288402ec70f9159022505cb3187e63b24df450), [`f527d1bb5a`](https://github.com/LedgerHQ/ledger-live/commit/f527d1bb5a2888a916f761d43d2ba5093eaa3e3f), [`a134f28e9d`](https://github.com/LedgerHQ/ledger-live/commit/a134f28e9d220d172148619ed281d4ca897d5532), [`cf2f585659`](https://github.com/LedgerHQ/ledger-live/commit/cf2f58565937b2a695ac7ff7d225cdbb6e598039), [`4dd486d87f`](https://github.com/LedgerHQ/ledger-live/commit/4dd486d87fea4c641cc4a21fc181c6097bab9d3d), [`a134f28e9d`](https://github.com/LedgerHQ/ledger-live/commit/a134f28e9d220d172148619ed281d4ca897d5532), [`b21de593ee`](https://github.com/LedgerHQ/ledger-live/commit/b21de593ee705ece38fc812eedb9bf85694e94cb), [`8b09b0b571`](https://github.com/LedgerHQ/ledger-live/commit/8b09b0b5717a47aedae5a8a80acf6d077af3b40b), [`49ea3fd98b`](https://github.com/LedgerHQ/ledger-live/commit/49ea3fd98ba1e1e0ed54d29ab5fdc71c4918183f), [`533278e2c4`](https://github.com/LedgerHQ/ledger-live/commit/533278e2c40ee764ecb87d4430fa6650f251ff0c), [`70e4277bc9`](https://github.com/LedgerHQ/ledger-live/commit/70e4277bc9dda253b894bdae5f2c8a5f43a9a64e)]: + - @ledgerhq/live-common@33.0.0 + - @ledgerhq/cryptoassets@11.0.0 + - @ledgerhq/coin-framework@0.7.0 + - @ledgerhq/live-env@0.6.0 + - @ledgerhq/live-network@1.1.7 + +## 22.12.1-next.0 + +### Patch Changes + +- Updated dependencies [[`61a891b06f`](https://github.com/LedgerHQ/ledger-live/commit/61a891b06f9028f285f87c321487f691272a9172)]: + - @ledgerhq/live-common@32.1.0-next.0 + +## 22.12.0 + +### Minor Changes + +- [#4851](https://github.com/LedgerHQ/ledger-live/pull/4851) [`6c83521fee`](https://github.com/LedgerHQ/ledger-live/commit/6c83521fee8da656858630c1cb37a5af95df3362) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Integrate injective + gas rework + +### Patch Changes + +- Updated dependencies [[`61272164de`](https://github.com/LedgerHQ/ledger-live/commit/61272164de6e81d9b5e5ad988b7eb8c40d3cf735), [`6c83521fee`](https://github.com/LedgerHQ/ledger-live/commit/6c83521fee8da656858630c1cb37a5af95df3362)]: + - @ledgerhq/live-common@31.8.0 + - @ledgerhq/cryptoassets@9.13.0 + - @ledgerhq/coin-framework@0.5.4 + ## 22.11.3 ### Patch Changes diff --git a/apps/cli/package.json b/apps/cli/package.json index 7ede9dd61f7b..bad391cc39ea 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -1,6 +1,6 @@ { "name": "@ledgerhq/live-cli", - "version": "22.11.3", + "version": "22.13.0", "description": "ledger-live CLI version", "repository": { "type": "git", @@ -60,8 +60,8 @@ "pako": "^2.0.4", "qrcode-terminal": "^0.12.0", "qrloop": "^1.2.0", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "rxjs": "^7.8.1", "winston": "^3.5.1", "ws": "^8.6.0" diff --git a/apps/cli/src/commands/bot.ts b/apps/cli/src/commands/bot.ts index b480fa949548..a6c769d657e0 100644 --- a/apps/cli/src/commands/bot.ts +++ b/apps/cli/src/commands/bot.ts @@ -30,6 +30,12 @@ export default { throw new Error("Please define a SEED env variable to run this bot."); } + if (arg.currency) { + // Remapping to match arg format in libs/ledger-live-common/src/bot/cli.ts + arg.filter = { currencies: [arg.currency] }; + delete arg.currency; + } + return from(bot(arg)); }, }; diff --git a/apps/cli/src/commands/getAddress.ts b/apps/cli/src/commands/getAddress.ts index 385300be23d4..7a5f7c9cff61 100644 --- a/apps/cli/src/commands/getAddress.ts +++ b/apps/cli/src/commands/getAddress.ts @@ -45,7 +45,6 @@ export default { throw new Error("--path is required"); } - asDerivationMode(arg.derivationMode as string); return withDevice(arg.device || "")(t => from( getAddress(t, { diff --git a/apps/cli/src/live-common-setup-base.ts b/apps/cli/src/live-common-setup-base.ts index 817d6c0c15e1..7048f7a79e15 100644 --- a/apps/cli/src/live-common-setup-base.ts +++ b/apps/cli/src/live-common-setup-base.ts @@ -76,6 +76,7 @@ setSupportedCurrencies([ "umee", "desmos", "onomy", + "sei_network", "persistence", "quicksilver", "internet_computer", diff --git a/apps/ledger-live-desktop/CHANGELOG.md b/apps/ledger-live-desktop/CHANGELOG.md index 14b12d60812d..d5a7d70fa210 100644 --- a/apps/ledger-live-desktop/CHANGELOG.md +++ b/apps/ledger-live-desktop/CHANGELOG.md @@ -1,5 +1,84 @@ # ledger-live-desktop +## 2.70.0 + +### Minor Changes + +- [#4741](https://github.com/LedgerHQ/ledger-live/pull/4741) [`a134f28e9d`](https://github.com/LedgerHQ/ledger-live/commit/a134f28e9d220d172148619ed281d4ca897d5532) Thanks [@chabroA](https://github.com/chabroA)! - Fix swap issue when estimating and editing fees + +- [#4583](https://github.com/LedgerHQ/ledger-live/pull/4583) [`f527d1bb5a`](https://github.com/LedgerHQ/ledger-live/commit/f527d1bb5a2888a916f761d43d2ba5093eaa3e3f) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Integrate injective + gas rework + +- [#4706](https://github.com/LedgerHQ/ledger-live/pull/4706) [`4dd486d87f`](https://github.com/LedgerHQ/ledger-live/commit/4dd486d87fea4c641cc4a21fc181c6097bab9d3d) Thanks [@Justkant](https://github.com/Justkant)! - feat: send LL version to the manifest-api + +- [#4285](https://github.com/LedgerHQ/ledger-live/pull/4285) [`533278e2c4`](https://github.com/LedgerHQ/ledger-live/commit/533278e2c40ee764ecb87d4430fa6650f251ff0c) Thanks [@chabroA](https://github.com/chabroA)! - Migrate Ethereum family implementation to EVM family + + Replace the legcay Ethereum familly implementation that was present in ledger-live-common by the coin-evm lib implementation. + This change was made in order to improve scalabillity and maintainability of the evm coins, as well as more easilly integrate new evm based chains in the future. + +### Patch Changes + +- [#4695](https://github.com/LedgerHQ/ledger-live/pull/4695) [`73217c9aa9`](https://github.com/LedgerHQ/ledger-live/commit/73217c9aa93c901d9c8d2067dcc7090243d35d35) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Update learn more link for cosmos redelegation banner to point to cosmos page instead of ethereum page. + +- [#4615](https://github.com/LedgerHQ/ledger-live/pull/4615) [`cf2f585659`](https://github.com/LedgerHQ/ledger-live/commit/cf2f58565937b2a695ac7ff7d225cdbb6e598039) Thanks [@sarneijim](https://github.com/sarneijim)! - Save swap history wallet api exchange + +- [#4861](https://github.com/LedgerHQ/ledger-live/pull/4861) [`0872f274dc`](https://github.com/LedgerHQ/ledger-live/commit/0872f274dceaddfdefc33cd2880476f44e8c43a4) Thanks [@cksanders](https://github.com/cksanders)! - Pass correct account ID, due to Platform SDK account ID not being equivalent to Wallet API account ID + + Includes fix for iOS and Android A series. + +- [#4705](https://github.com/LedgerHQ/ledger-live/pull/4705) [`a4a6fda329`](https://github.com/LedgerHQ/ledger-live/commit/a4a6fda329ae44b54a3216ddebde41792dfa8b30) Thanks [@ofreyssinet-ledger](https://github.com/ofreyssinet-ledger)! - Fix Stax onboarding early security checks: infinite loading state for locked device + +- [#4792](https://github.com/LedgerHQ/ledger-live/pull/4792) [`260b3811dd`](https://github.com/LedgerHQ/ledger-live/commit/260b3811dd4804ab02dd52b9a6ab4d738e28b656) Thanks [@sarneijim](https://github.com/sarneijim)! - Add account wallet id conversion for buy deeplinks + +- [#4648](https://github.com/LedgerHQ/ledger-live/pull/4648) [`8b09b0b571`](https://github.com/LedgerHQ/ledger-live/commit/8b09b0b5717a47aedae5a8a80acf6d077af3b40b) Thanks [@cksanders](https://github.com/cksanders)! - Update multibuy manifest to v2 to ensure full backwards compatibility + +- [#4685](https://github.com/LedgerHQ/ledger-live/pull/4685) [`35cb442294`](https://github.com/LedgerHQ/ledger-live/commit/35cb4422944f1e7af696c816a53a6ada74525de2) Thanks [@beths-ledger](https://github.com/beths-ledger)! - Conditionally render different text when user arrives at the buy funds modal from a get funds button rather than default of no funds. Applies to mobile and desktop. + +- [#4717](https://github.com/LedgerHQ/ledger-live/pull/4717) [`a80310f16a`](https://github.com/LedgerHQ/ledger-live/commit/a80310f16af3f22f71052d0f3696ab8b7a652a77) Thanks [@lvndry](https://github.com/lvndry)! - Update ethereum staking icon + +- [#4588](https://github.com/LedgerHQ/ledger-live/pull/4588) [`c89f7d0e9e`](https://github.com/LedgerHQ/ledger-live/commit/c89f7d0e9e37f4389578c2833adde076a5811ff5) Thanks [@aboissiere-ledger](https://github.com/aboissiere-ledger)! - Fix jest config to generate coverage report and include untested files + +- [#4533](https://github.com/LedgerHQ/ledger-live/pull/4533) [`70e4277bc9`](https://github.com/LedgerHQ/ledger-live/commit/70e4277bc9dda253b894bdae5f2c8a5f43a9a64e) Thanks [@sshmaxime](https://github.com/sshmaxime)! - Typed useFeature hook + +- Updated dependencies [[`51857f5c20`](https://github.com/LedgerHQ/ledger-live/commit/51857f5c2016d435fa970fac899aa906e3f97722), [`61a891b06f`](https://github.com/LedgerHQ/ledger-live/commit/61a891b06f9028f285f87c321487f691272a9172), [`f527d1bb5a`](https://github.com/LedgerHQ/ledger-live/commit/f527d1bb5a2888a916f761d43d2ba5093eaa3e3f), [`a134f28e9d`](https://github.com/LedgerHQ/ledger-live/commit/a134f28e9d220d172148619ed281d4ca897d5532), [`cf2f585659`](https://github.com/LedgerHQ/ledger-live/commit/cf2f58565937b2a695ac7ff7d225cdbb6e598039), [`a134f28e9d`](https://github.com/LedgerHQ/ledger-live/commit/a134f28e9d220d172148619ed281d4ca897d5532), [`4dd486d87f`](https://github.com/LedgerHQ/ledger-live/commit/4dd486d87fea4c641cc4a21fc181c6097bab9d3d), [`4cb507a52b`](https://github.com/LedgerHQ/ledger-live/commit/4cb507a52bf336d395b08b4c1a429bd4956ab22d), [`b21de593ee`](https://github.com/LedgerHQ/ledger-live/commit/b21de593ee705ece38fc812eedb9bf85694e94cb), [`8b09b0b571`](https://github.com/LedgerHQ/ledger-live/commit/8b09b0b5717a47aedae5a8a80acf6d077af3b40b), [`b779f6c964`](https://github.com/LedgerHQ/ledger-live/commit/b779f6c964079b9cd9a4ee985cd5cdbb8c49406e), [`533278e2c4`](https://github.com/LedgerHQ/ledger-live/commit/533278e2c40ee764ecb87d4430fa6650f251ff0c), [`70e4277bc9`](https://github.com/LedgerHQ/ledger-live/commit/70e4277bc9dda253b894bdae5f2c8a5f43a9a64e)]: + - @ledgerhq/live-common@33.0.0 + - @ledgerhq/types-cryptoassets@7.6.0 + - @ledgerhq/types-live@6.41.0 + - @ledgerhq/coin-evm@0.8.0 + - @ledgerhq/coin-framework@0.7.0 + - @ledgerhq/live-env@0.6.0 + - @ledgerhq/domain-service@1.1.12 + - @ledgerhq/live-network@1.1.7 + +## 2.69.1-next.0 + +### Patch Changes + +- Updated dependencies [[`61a891b06f`](https://github.com/LedgerHQ/ledger-live/commit/61a891b06f9028f285f87c321487f691272a9172)]: + - @ledgerhq/live-common@32.1.0-next.0 + +## 2.69.0 + +### Minor Changes + +- [#4851](https://github.com/LedgerHQ/ledger-live/pull/4851) [`6c83521fee`](https://github.com/LedgerHQ/ledger-live/commit/6c83521fee8da656858630c1cb37a5af95df3362) Thanks [@hedi-edelbloute](https://github.com/hedi-edelbloute)! - Integrate injective + gas rework + +### Patch Changes + +- Updated dependencies [[`61272164de`](https://github.com/LedgerHQ/ledger-live/commit/61272164de6e81d9b5e5ad988b7eb8c40d3cf735), [`6c83521fee`](https://github.com/LedgerHQ/ledger-live/commit/6c83521fee8da656858630c1cb37a5af95df3362)]: + - @ledgerhq/live-common@31.8.0 + - @ledgerhq/types-cryptoassets@7.5.0 + - @ledgerhq/types-live@6.40.0 + - @ledgerhq/coin-evm@0.6.2 + - @ledgerhq/coin-framework@0.5.4 + - @ledgerhq/domain-service@1.1.11 + - @ledgerhq/evm-tools@1.0.7 + +### Patch Changes + +- Updated dependencies [[`b779f6c964`](https://github.com/LedgerHQ/ledger-live/commit/b779f6c964079b9cd9a4ee985cd5cdbb8c49406e)]: + - @ledgerhq/coin-evm@0.7.0-next.1 + - @ledgerhq/live-common@32.0.0-next.1 + ## 2.68.1 ### Patch Changes diff --git a/apps/ledger-live-desktop/RELEASE_NOTES.md b/apps/ledger-live-desktop/RELEASE_NOTES.md index d2c5312d0346..6ad6d1bf6aa8 100644 --- a/apps/ledger-live-desktop/RELEASE_NOTES.md +++ b/apps/ledger-live-desktop/RELEASE_NOTES.md @@ -1,3 +1,7 @@ +# 2.69.0 + +This release includes minor bug fixes and security improvements. + # 2.68.1 This release includes minor bug fixes and security improvements. @@ -6,13 +10,13 @@ This release includes minor bug fixes and security improvements. ### 🚀 Features -Starting today, you can stake Cardano (ADA) through Ledger Live and earn rewards. +Starting today, you can stake Cardano (ADA) through Ledger Live and earn rewards. When swapping crypto assets, a warning message will alert you if you don’t have enough funds to pay the network fees. ### 🐛 Fixes -Optimism is now Op Mainnet. We’ve made the name change in Ledger Live. +Optimism is now Op Mainnet. We’ve made the name change in Ledger Live. # 2.64.2 diff --git a/apps/ledger-live-desktop/cryptoassets.md b/apps/ledger-live-desktop/cryptoassets.md index d40b67d4a716..0493e92a78c1 100644 --- a/apps/ledger-live-desktop/cryptoassets.md +++ b/apps/ledger-live-desktop/cryptoassets.md @@ -60,6 +60,7 @@ | Quicksilver | QCK | YES | quicksilver | | RSK | RBTC | YES | rsk | | SecretNetwork | SCRT | YES | secret_network | +| SeiNetwork | SEI | YES | sei_network | | Solana | SOL | YES | solana | | Songbird | SGB | YES | songbird | | Stacks | STX | YES | stacks | @@ -126,7 +127,6 @@ | Ravencoin | RVN | NO | ravencoin | | Resistance | RES | NO | resistance | | Rise | RISE | NO | rise | -| SeiNetwork | SEI | NO | sei_network | | Shyft | SHFT | NO | shyft | | Stride | STRD | NO | stride | | Thundercore | TT | NO | thundercore | diff --git a/apps/ledger-live-desktop/package.json b/apps/ledger-live-desktop/package.json index 76a36eb9c5eb..d6276c4e4fb7 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.68.1", + "version": "2.70.0", "scripts": { "start:prod": "electron ./.webpack/main.bundle.js", "start": "cross-env NODE_ENV=development node ./tools/main.js", @@ -93,8 +93,8 @@ "prop-types": "^15.8.1", "qrcode": "^1.4.4", "qrloop": "1.4.1", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", "react-easy-crop": "^4.5.0", "react-i18next": "^13.1.2", "react-intersection-observer": "^8.32.4", @@ -141,7 +141,7 @@ "@ledgerhq/react-devtools": "workspace:^", "@ledgerhq/test-utils": "workspace:^", "@octokit/rest": "^18.12.0", - "@playwright/test": "^1.34.3", + "@playwright/test": "^1.38.1", "@sentry/cli": "^2.13.0", "@sentry/types": "^7.47.0", "@testing-library/dom": "^9.3.1", @@ -154,8 +154,8 @@ "@types/invariant": "^2.2.35", "@types/jest": "^28.1.8", "@types/lodash": "^4.14.182", - "@types/react": "^17.0.53", - "@types/react-dom": "^17", + "@types/react": "^18.2.21", + "@types/react-dom": "^18.2.13", "@types/react-lottie": "^1.2.6", "@types/react-motion": "^0.0.34", "@types/react-redux": "^7.1.24", @@ -176,17 +176,17 @@ "@types/write-file-atomic": "^4.0.0", "@types/zxcvbn": "^4.4.1", "@vitejs/plugin-react": "^3.1.0", - "allure-playwright": "^2.0.0-beta.20", + "allure-playwright": "2.8.1", "axios": "^1.3.4", "chalk": "^4.1.2", "cross-env": "^7.0.3", "debug": "^4.3.4", - "electron": "^25.1.1", + "electron": "^25.9.1", "electron-builder": "^23.6.0", "electron-devtools-installer": "^3.2.0", "esbuild-utils": "workspace:*", - "eslint-plugin-jest": "^27.2.1", - "eslint-plugin-react": "^7.32.2", + "eslint-plugin-jest": "^27.4.2", + "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "execa": "^8.0.0", "hasha": "^5.2.2", @@ -198,7 +198,7 @@ "native-modules-tools": "workspace:*", "prebuild-install": "^7.1.1", "react-refresh": "^0.14.0", - "react-test-renderer": "^17.0.2", + "react-test-renderer": "^18.2.0", "serve-handler": "^6.1.3", "ts-jest": "^28.0.8", "vite": "^4.1.1", diff --git a/apps/ledger-live-desktop/scripts/beforePack.js b/apps/ledger-live-desktop/scripts/beforePack.js index 67163e07858b..8b07cc25e45c 100644 --- a/apps/ledger-live-desktop/scripts/beforePack.js +++ b/apps/ledger-live-desktop/scripts/beforePack.js @@ -3,11 +3,11 @@ const fs = require("fs"); const { processNativeModules } = require("native-modules-tools"); const lldRoot = path.resolve(__dirname, ".."); -exports.default = async function(context) { +exports.default = async function (context) { // Rebuild native modules await context.packager.info.installAppDependencies(context.packager.platform, context.arch); // Remove previous node_modules fs.rmSync(path.join(lldRoot, "dist", "node_modules"), { recursive: true }); // Find native modules and copy them to ./dist/node_modules with their dependencies. - processNativeModules({ root: lldRoot, destination: "dist", silent: true }); + await processNativeModules({ root: lldRoot, destination: "dist", silent: true }); }; diff --git a/apps/ledger-live-desktop/src/config/urls.ts b/apps/ledger-live-desktop/src/config/urls.ts index e7aeaa79e082..d59b0bfd8373 100644 --- a/apps/ledger-live-desktop/src/config/urls.ts +++ b/apps/ledger-live-desktop/src/config/urls.ts @@ -14,6 +14,7 @@ export const supportLinkByTokenType = { }; const errors: Record = { + NotEnoughGas: "https://support.ledger.com/hc/en-us/articles/9096370252573?support=true", CantOpenDevice: "https://support.ledger.com/hc/en-us/articles/115005165269?utm_source=ledger_live_desktop&utm_medium=self_referral&utm_content=error_cantopendevice", WrongDeviceForAccount: diff --git a/apps/ledger-live-desktop/src/generate-cryptoassets-md.test.ts b/apps/ledger-live-desktop/src/generate-cryptoassets-md.test.ts index ba27a06bc60f..5099e386c783 100644 --- a/apps/ledger-live-desktop/src/generate-cryptoassets-md.test.ts +++ b/apps/ledger-live-desktop/src/generate-cryptoassets-md.test.ts @@ -1,6 +1,7 @@ // it is a bit a hack but it's a test that run in jest // to access the libs / babel ecosystem and generate a markdown file! // it passes if the file doesn't change (like a snapshot!) +// to run this test: pnpm desktop test:jest src/generate-cryptoassets-md.test.ts import { test, expect } from "@jest/globals"; import fs from "fs"; import "./live-common-set-supported-currencies"; diff --git a/apps/ledger-live-desktop/src/internal/transportHandler.ts b/apps/ledger-live-desktop/src/internal/transportHandler.ts index 0d7cd01caf79..206c05241cf9 100644 --- a/apps/ledger-live-desktop/src/internal/transportHandler.ts +++ b/apps/ledger-live-desktop/src/internal/transportHandler.ts @@ -43,19 +43,21 @@ export const transportOpen = ({ data, requestId }: MessagesMap["transport:open"] if (e.type === "exchange") { transport .exchange(Buffer.from(e.apduHex, "hex")) - .then(response => - process.send?.({ - type: transportExchangeChannel, - data: response.toString("hex"), - requestId: e.requestId, - }), + .then( + response => + process.send?.({ + type: transportExchangeChannel, + data: response.toString("hex"), + requestId: e.requestId, + }), ) - .catch(error => - process.send?.({ - type: transportExchangeChannel, - error: serializeError(error), - requestId: e.requestId, - }), + .catch( + error => + process.send?.({ + type: transportExchangeChannel, + error: serializeError(error), + requestId: e.requestId, + }), ); } else if (e.type === "exchangeBulk") { const apdus = e.apdusHex.map(apduHex => Buffer.from(apduHex, "hex")); diff --git a/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts b/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts index 5ddc50fa4c04..8275c57ce654 100644 --- a/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts +++ b/apps/ledger-live-desktop/src/live-common-set-supported-currencies.ts @@ -9,6 +9,7 @@ setSupportedCurrencies([ "umee", "desmos", "onomy", + "sei_network", "quicksilver", "persistence", "avalanche_c_chain", diff --git a/apps/ledger-live-desktop/src/live-common-setup-base.ts b/apps/ledger-live-desktop/src/live-common-setup-base.ts index f0512be60f90..7ee33e8310ec 100644 --- a/apps/ledger-live-desktop/src/live-common-setup-base.ts +++ b/apps/ledger-live-desktop/src/live-common-setup-base.ts @@ -1,4 +1,3 @@ -import "./env"; import { setEnv } from "@ledgerhq/live-env"; if (process.env.NODE_ENV === "production") { const value = `lld/${__APP_VERSION__}`; diff --git a/apps/ledger-live-desktop/src/env.ts b/apps/ledger-live-desktop/src/main/env.ts similarity index 100% rename from apps/ledger-live-desktop/src/env.ts rename to apps/ledger-live-desktop/src/main/env.ts diff --git a/apps/ledger-live-desktop/src/main/setup.ts b/apps/ledger-live-desktop/src/main/setup.ts index 0475c41895dc..fa529e2ab3d5 100644 --- a/apps/ledger-live-desktop/src/main/setup.ts +++ b/apps/ledger-live-desktop/src/main/setup.ts @@ -1,3 +1,4 @@ +import "./env"; import "~/live-common-setup-base"; import { captureException } from "~/sentry/main"; import { ipcMain } from "electron"; diff --git a/apps/ledger-live-desktop/src/renderer/Default.tsx b/apps/ledger-live-desktop/src/renderer/Default.tsx index e6a945fc5087..b3d32f2fc89c 100644 --- a/apps/ledger-live-desktop/src/renderer/Default.tsx +++ b/apps/ledger-live-desktop/src/renderer/Default.tsx @@ -59,7 +59,6 @@ import { hasCompletedOnboardingSelector } from "~/renderer/reducers/settings"; import Market from "~/renderer/screens/market"; import MarketCoinScreen from "~/renderer/screens/market/MarketCoinScreen"; import Learn from "~/renderer/screens/learn"; -import { useProviders } from "~/renderer/screens/exchange/Swap2/Form"; import WelcomeScreenSettings from "~/renderer/screens/settings/WelcomeScreenSettings"; import SyncOnboarding from "./components/SyncOnboarding"; import RecoverPlayer from "~/renderer/screens/recover/Player"; @@ -67,6 +66,10 @@ import { updateIdentify } from "./analytics/segment"; import { useDiscoverDB } from "./screens/platform/v2/hooks"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import { enableListAppsV2 } from "@ledgerhq/live-common/apps/hw"; +import { + useFetchCurrencyAll, + useFetchCurrencyFrom, +} from "@ledgerhq/live-common/exchange/swap/hooks/index"; // in order to test sentry integration, we need the ability to test it out. const LetThisCrashForCrashTest = () => { @@ -147,7 +150,8 @@ export default function Default() { useListenToHidDevices(); useDeeplink(); useUSBTroubleshooting(); - useProviders(); // prefetch data from swap providers here + useFetchCurrencyAll(); + useFetchCurrencyFrom(); const discoverDB = useDiscoverDB(); const listAppsV2 = useFeature("listAppsV2"); diff --git a/apps/ledger-live-desktop/src/renderer/actions/UI.ts b/apps/ledger-live-desktop/src/renderer/actions/UI.ts index 73d62a75e20a..360d6e88ecd0 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/UI.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/UI.ts @@ -1,4 +1,5 @@ import { LiveAppManifest } from "@ledgerhq/live-common/platform/types"; +import { AppManifest } from "@ledgerhq/live-common/wallet-api/types"; import { createAction } from "redux-actions"; export const openInformationCenter = createAction( "INFORMATION_CENTER_OPEN", @@ -30,7 +31,7 @@ export const openPlatformAppDisclaimerDrawer = createAction( }: { manifest: LiveAppManifest | undefined | null; disclaimerId: string; - next: () => void; + next: (manifest: AppManifest, isChecked: boolean) => void; }) => ({ type: "DAPP_DISCLAIMER", manifest, diff --git a/apps/ledger-live-desktop/src/renderer/actions/swap.ts b/apps/ledger-live-desktop/src/renderer/actions/swap.ts index 47b5515edf5a..142262fd9765 100644 --- a/apps/ledger-live-desktop/src/renderer/actions/swap.ts +++ b/apps/ledger-live-desktop/src/renderer/actions/swap.ts @@ -1,7 +1,5 @@ -import { getAccountCurrency } from "@ledgerhq/live-common/account/index"; -import { flattenAccounts } from "@ledgerhq/live-common/account/helpers"; import { Transaction } from "@ledgerhq/live-common/generated/types"; -import { Account, TokenAccount } from "@ledgerhq/types-live"; +import { Account } from "@ledgerhq/types-live"; import memoize from "lodash/memoize"; import { createAction } from "redux-actions"; import { createSelector } from "reselect"; @@ -38,44 +36,12 @@ export const filterAvailableToAssets = (pairs: Pair[] | null | undefined, fromId toAssets.push(pair.to); } } - return toAssets; -}; - -const filterAvailableFromAssets = ( - pairs: Pair[] | undefined | null, - allAccounts: Account[], -): (Account & { disabled: boolean })[] => { - if (pairs === null || pairs === undefined) return []; - return flattenAccounts(allAccounts).map(account => { - const id = getAccountCurrency(account).id; - const isAccountAvailable = !!pairs.find(pair => pair.from === id); - return { - ...account, - disabled: !isAccountAvailable, - }; - }) as (Account & { disabled: boolean })[]; + return [...new Set(toAssets)]; }; export const toSelector = createSelector( (state: State) => state.swap.pairs, - pairs => - memoize((fromId?: string) => { - const filteredAssets = filterAvailableToAssets(pairs, fromId); - const uniqueAssetList = [...new Set(filteredAssets)]; - return uniqueAssetList; - }), -); - -export const fromSelector = createSelector( - (state: State) => { - return state.swap.pairs; - }, - pairs => { - return memoize( - (allAccounts: Array): Array => - sortAccountsByStatus(filterAvailableFromAssets(pairs, allAccounts)), - ); - }, + pairs => memoize((fromId?: string) => filterAvailableToAssets(pairs, fromId)), ); // Put disabled accounts and subaccounts at the bottom of the list while preserving the parent/children position. diff --git a/apps/ledger-live-desktop/src/renderer/animations/index.tsx b/apps/ledger-live-desktop/src/renderer/animations/index.tsx index dd9df5cd8efc..bb58f20ceb10 100644 --- a/apps/ledger-live-desktop/src/renderer/animations/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/animations/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import Lottie, { LottieProps } from "react-lottie"; import { Flex } from "@ledgerhq/react-ui"; +import { getEnv } from "@ledgerhq/live-env"; const Animation = ({ animation, loop = true, @@ -21,8 +22,10 @@ const Animation = ({ rendererSettings?: LottieProps["options"]["rendererSettings"]; isPaused?: boolean; isStopped?: boolean; -}) => - animation ? ( +}) => { + // in case of playwright tests, we want to completely stop the animation + const isPlaywright = !!getEnv("PLAYWRIGHT_RUN"); + return animation ? ( ) : null; +}; export default Animation; diff --git a/apps/ledger-live-desktop/src/renderer/bridge/BridgeSyncContext.tsx b/apps/ledger-live-desktop/src/renderer/bridge/BridgeSyncContext.tsx index 9a0d25f95442..6ab332a59ec4 100644 --- a/apps/ledger-live-desktop/src/renderer/bridge/BridgeSyncContext.tsx +++ b/apps/ledger-live-desktop/src/renderer/bridge/BridgeSyncContext.tsx @@ -9,15 +9,17 @@ import { recentlyKilledInternalProcess } from "~/renderer/reset"; import { track } from "~/renderer/analytics/segment"; import { prepareCurrency, hydrateCurrency } from "./cache"; import { blacklistedTokenIdsSelector } from "~/renderer/reducers/settings"; +import { Account } from "@ledgerhq/types-live"; export const BridgeSyncProvider = ({ children }: { children: React.ReactNode }) => { const accounts = useSelector(accountsSelector); const blacklistedTokenIds = useSelector(blacklistedTokenIdsSelector); const dispatch = useDispatch(); const updateAccount = useCallback( - (accountId, updater) => dispatch(updateAccountWithUpdater(accountId, updater)), + (accountId: string, updater: (a: Account) => Account) => + dispatch(updateAccountWithUpdater(accountId, updater)), [dispatch], ); - const recoverError = useCallback(error => { + const recoverError = useCallback((error: Error) => { const isInternalProcessError = error && error.message.includes("Internal process error"); if ( isInternalProcessError && diff --git a/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/types.ts b/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/types.ts index 25abaee42139..811165352042 100644 --- a/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/types.ts +++ b/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/types.ts @@ -1,5 +1,5 @@ import { LoggableEvent } from "~/renderer/analytics/segment"; export type LoggableEventRenderable = LoggableEvent & { - id: string; + id: number; }; diff --git a/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/useAnalyticsEventsLog.ts b/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/useAnalyticsEventsLog.ts index a57ba1588999..461fbff5993f 100644 --- a/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/useAnalyticsEventsLog.ts +++ b/apps/ledger-live-desktop/src/renderer/components/AnalyticsConsole/useAnalyticsEventsLog.ts @@ -7,7 +7,7 @@ export default function useAnalyticsEventsLog(limit = 40) { const id = useRef(0); const [items, setItems] = useState([]); const addItem = useCallback( - item => { + (item: LoggableEventRenderable) => { setItems(currentItems => [...currentItems.slice(-(limit - 1)), item]); }, [limit], diff --git a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AccountCrumb.tsx b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AccountCrumb.tsx index f49c317fda57..684835bf35ee 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AccountCrumb.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AccountCrumb.tsx @@ -21,6 +21,12 @@ import CryptoCurrencyIcon from "~/renderer/components/CryptoCurrencyIcon"; import { Separator, Item, TextLink, AngleDown, Check } from "./common"; import { setTrackingSource } from "~/renderer/analytics/TrackPage"; +type ItemShape = { + key: string; + label: string; + account: Account | SubAccount; +}; + const AccountCrumb = () => { const history = useHistory(); const { t } = useTranslation(); @@ -53,7 +59,7 @@ const AccountCrumb = () => { [parentId, account, accounts], ); - const renderItem = useCallback(({ item, isActive }) => { + const renderItem = useCallback(({ item, isActive }: { item: ItemShape; isActive: boolean }) => { const currency = getAccountCurrency(item.account); return ( @@ -71,7 +77,7 @@ const AccountCrumb = () => { }, []); const onAccountSelected = useCallback( - item => { + (item: ItemShape) => { if (!item) { return; } diff --git a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AssetCrumb.tsx b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AssetCrumb.tsx index 5c357951d17e..3ae02ea698ac 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AssetCrumb.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/AssetCrumb.tsx @@ -12,13 +12,21 @@ import CryptoCurrencyIcon from "~/renderer/components/CryptoCurrencyIcon"; import { Separator, Item, TextLink, AngleDown, Check } from "./common"; import { setTrackingSource } from "~/renderer/analytics/TrackPage"; import { DistributionItem } from "@ledgerhq/types-live"; +import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; + +type ItemShape = { + key: string; + label: string; + currency: CryptoCurrency | TokenCurrency; +}; + export default function AssetCrumb() { const { t } = useTranslation(); const distribution = useDistribution(); const history = useHistory(); const { assetId } = useParams<{ assetId?: string }>(); const renderItem = useCallback( - ({ item, isActive }) => ( + ({ item, isActive }: { item: ItemShape; isActive: boolean }) => ( @@ -34,7 +42,7 @@ export default function AssetCrumb() { [], ); const onAccountSelected = useCallback( - item => { + (item: ItemShape) => { if (!item) { return; } diff --git a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/NFTCrumb.tsx b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/NFTCrumb.tsx index 5779582e7a60..19a663bd4185 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/NFTCrumb.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Breadcrumb/NFTCrumb.tsx @@ -59,7 +59,7 @@ const NFTCrumb = () => { [collectionAddress, items], ); const onCollectionSelected = useCallback( - item => { + (item: DropDownItemType) => { if (!item) return; setTrackingSource("NFT breadcrumb"); history.push({ diff --git a/apps/ledger-live-desktop/src/renderer/components/BuyButton.tsx b/apps/ledger-live-desktop/src/renderer/components/BuyButton.tsx index 26818e0cd1f2..089129dff0c3 100644 --- a/apps/ledger-live-desktop/src/renderer/components/BuyButton.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/BuyButton.tsx @@ -31,7 +31,7 @@ const BuyButton = ({ currency, account }: { currency: CryptoCurrency; account: A } return ( - - ) : ( - - )} - - {title && ( - - {title} - - )} - - {onRequestClose && !deviceBlocked ? ( - - - - ) : ( - - )} - - ) : null} + {children} p.theme.colors.palette.text.shade80}; + transition: filter 150ms ease-out; + cursor: pointer; + + :hover { + filter: opacity(0.8); + } + :active { + filter: opacity(0.5); + } +`; + +type Props = { + title?: string; + onRequestClose?: (a: React.MouseEvent) => void; + onRequestBack?: (a: React.MouseEvent) => void; +}; +const SideDrawerHeader = ({ title, onRequestClose, onRequestBack }: Props) => { + const blocked = useDeviceBlocked(); + + return ( + <> + {onRequestClose || onRequestBack || title ? ( + + {onRequestBack ? ( + + ) : ( + + )} + + {title && ( + + {title} + + )} + + {onRequestClose && !blocked ? ( + + + + ) : ( + + )} + + ) : null} + + ); +}; + +export default SideDrawerHeader; diff --git a/apps/ledger-live-desktop/src/renderer/components/Slider.tsx b/apps/ledger-live-desktop/src/renderer/components/Slider.tsx index 24e3e2e2cfd5..16eaaeeabb98 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Slider.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Slider.tsx @@ -92,7 +92,7 @@ const Slider = ({ steps, value, onChange, error, theme }: Props) => { const root = useRef(null); const internalPadding = 12; const reverseX = useCallback( - x => { + (x: number) => { if (!root.current) return 0; const { width } = root.current.getBoundingClientRect(); return Math.max( @@ -106,13 +106,13 @@ const Slider = ({ steps, value, onChange, error, theme }: Props) => { [steps, root], ); const concernedEvent = useCallback( - e => { - if (!e.targetTouches) { + (e: unknown) => { + if (!(e as TouchEvent).targetTouches) { return e; } - if (!down) return e.targetTouches[0]; + if (!down) return (e as TouchEvent).targetTouches[0]; const touchId = down.touchId; - const items = e.changedTouches; + const items = (e as TouchEvent).changedTouches; for (let i = 0; i < items.length; ++i) { if (items[i].identifier === touchId) return items[i]; } @@ -121,13 +121,13 @@ const Slider = ({ steps, value, onChange, error, theme }: Props) => { [down], ); const onHandleStart = useCallback( - e => { + (e: MouseEvent) => { const event = concernedEvent(e); if (!event) return; e.preventDefault(); - const x = xForEvent(root.current, event); + const x = xForEvent(root.current, event as MouseEvent); setDown({ - touchId: event.identifier, + touchId: (event as { identifier: number }).identifier, x, }); const valuePos = reverseX(x); @@ -136,18 +136,18 @@ const Slider = ({ steps, value, onChange, error, theme }: Props) => { [root, concernedEvent, reverseX, onChange, value], ); const onHandleMove = useCallback( - e => { + (e: MouseEvent) => { const event = concernedEvent(e); if (!event) return; e.preventDefault(); - const x = xForEvent(root.current, event); + const x = xForEvent(root.current, event as MouseEvent); const valuePos = reverseX(x); if (value !== valuePos) onChange(valuePos); }, [root, concernedEvent, reverseX, value, onChange], ); const onHandleEnd = useCallback( - e => { + (e: MouseEvent) => { const event = concernedEvent(e); if (!event) return; setDown(null); @@ -185,6 +185,7 @@ const Slider = ({ steps, value, onChange, error, theme }: Props) => { const palette = getPalette(theme); const colors = palette[error ? "error" : "default"]; return ( + // @ts-expect-error weird events stuff
= useCallback( e => { track(isAccountStarred ? "Account Unstar" : "Account Star"); e.stopPropagation(); diff --git a/apps/ledger-live-desktop/src/renderer/components/Stepper/index.tsx b/apps/ledger-live-desktop/src/renderer/components/Stepper/index.tsx index 61f7a613eb9e..24b3465645a9 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Stepper/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Stepper/index.tsx @@ -54,7 +54,7 @@ const Stepper = ({ }: Props) => { const deviceBlocked = useDeviceBlocked(); const transitionTo = useCallback( - stepId => { + (stepId: number) => { const stepIndex = steps.findIndex(s => s.id === stepId); const step = steps[stepIndex]; invariant(step, "Stepper: step %s doesn't exists", stepId); diff --git a/apps/ledger-live-desktop/src/renderer/components/SuccessAnimatedIcon.tsx b/apps/ledger-live-desktop/src/renderer/components/SuccessAnimatedIcon.tsx index 3f39181250e7..62a53838c67c 100644 --- a/apps/ledger-live-desktop/src/renderer/components/SuccessAnimatedIcon.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/SuccessAnimatedIcon.tsx @@ -73,14 +73,16 @@ const SuccessLogoContainer = styled(Box).attrs<{ & > circle { stroke-dasharray: 151px, 151px; stroke: #66be54; - animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both ${drawCircle}, + animation: + 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both ${drawCircle}, 0.3s linear 0.9s 1 both ${fadeOut}; } & > polyline { stroke-dasharray: 151px, 151px; stroke: #66be54; - animation: 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both ${drawCheck}, + animation: + 1s cubic-bezier(0.77, 0, 0.175, 1) 0s 1 both ${drawCheck}, 0.3s linear 0.9s 1 both ${fadeOut}; } } diff --git a/apps/ledger-live-desktop/src/renderer/components/Switch.tsx b/apps/ledger-live-desktop/src/renderer/components/Switch.tsx index 78829efabc90..2acf9ad80c73 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Switch.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Switch.tsx @@ -64,7 +64,7 @@ const Ball = styled.div` type Props = { isChecked: boolean; disabled?: boolean; - onChange?: Function; + onChange?: (a: boolean) => void; small?: boolean; medium?: boolean; forceBgColor?: string; diff --git a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/Body.tsx b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/Body.tsx index 6615c6b6caf8..8f3d7361f2a7 100644 --- a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/Body.tsx @@ -122,7 +122,9 @@ const SoftwareCheckContent = ({ {updateSkippable ? ( ) : null} diff --git a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/ErrorDrawer.tsx b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/ErrorDrawer.tsx index ecadfee6afef..deb42b1c20e9 100644 --- a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/ErrorDrawer.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/ErrorDrawer.tsx @@ -99,7 +99,7 @@ const ErrorDrawer: React.FC = ({ error, onClickRetry, closeable = false } onClickRetry(); }} > - {t("syncOnboarding.manual.softwareCheckContent.genuineCheckErrorDrawer.retryCTA")} + {t("common.tryAgain")} )} diff --git a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/index.tsx b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/index.tsx index 8e5c41a52bf3..6c0a8c3852d3 100644 --- a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/EarlySecurityChecks/index.tsx @@ -4,7 +4,9 @@ import manager from "@ledgerhq/live-common/manager/index"; import { useGenuineCheck } from "@ledgerhq/live-common/hw/hooks/useGenuineCheck"; import { useGetLatestAvailableFirmware } from "@ledgerhq/live-common/deviceSDK/hooks/useGetLatestAvailableFirmware"; import Body from "./Body"; -import LockedDeviceDrawer, { Props as LockedDeviceDrawerProps } from "../LockedDeviceDrawer"; +import TroubleshootingDrawer, { + Props as TroubleshootingDrawerProps, +} from "../TroubleshootingDrawer"; import SoftwareCheckAllowSecureChannelDrawer, { Props as SoftwareCheckAllowSecureChannelDrawerProps, } from "./SoftwareCheckAllowSecureChannelDrawer"; @@ -27,6 +29,7 @@ import { track } from "~/renderer/analytics/segment"; import { log } from "@ledgerhq/logs"; import { useDynamicUrl } from "~/renderer/terms"; import { FinalFirmware } from "@ledgerhq/types-live"; +import { useHistory } from "react-router-dom"; export type Props = { onComplete: () => void; @@ -79,6 +82,7 @@ const EarlySecurityChecks = ({ SoftwareCheckStatus.inactive, ); const [availableFirmwareVersion, setAvailableFirmwareVersion] = useState(""); + const history = useHistory(); const deviceId = device.deviceId ?? ""; const deviceModelId = device.modelId; @@ -136,6 +140,11 @@ const EarlySecurityChecks = ({ setFwUpdateInterrupted(latestFirmware?.final); restartChecksAfterUpdate(); }, + onRequestClose: () => { + closeFwUpdateDrawer(); + setFwUpdateInterrupted(latestFirmware.final); + restartChecksAfterUpdate(); + }, status: modal, stepId, firmware: latestFirmware, @@ -161,11 +170,8 @@ const EarlySecurityChecks = ({ setDrawer(UpdateFirmwareModal, updateFirmwareModalProps, { preventBackdropClick: true, forceDisableFocusTrap: true, - onRequestClose: () => { - closeFwUpdateDrawer(); - setFwUpdateInterrupted(latestFirmware.final); - restartChecksAfterUpdate(); - }, + withPaddingTop: false, + onRequestClose: undefined, }); }, [ closeFwUpdateDrawer, @@ -227,7 +233,8 @@ const EarlySecurityChecks = ({ getLatestAvailableFirmwareError, ]); - const lockedDeviceModalIsOpen = + // at this step we can't have an unlocked device; it's inevitably disconnected + const disconnectedDeviceModalIsOpen = (devicePermissionState === "unlock-needed" && genuineCheckActive) || (lockedDevice && firmwareUpdateStatus === SoftwareCheckStatus.active); @@ -239,11 +246,15 @@ const EarlySecurityChecks = ({ /** Opening and closing of drawers */ useEffect(() => { - if (lockedDeviceModalIsOpen) { - const props: LockedDeviceDrawerProps = { - deviceModelId, + if (disconnectedDeviceModalIsOpen) { + const props: TroubleshootingDrawerProps = { + lastKnownDeviceId: deviceModelId, + onClose: () => { + resetGenuineCheckState(); + history.push("/onboarding/select-device"); + }, }; - setDrawer(LockedDeviceDrawer, props, commonDrawerProps); + setDrawer(TroubleshootingDrawer, props, commonDrawerProps); } else if (allowSecureChannelIsOpen) { const props: SoftwareCheckAllowSecureChannelDrawerProps = { deviceModelId, @@ -294,10 +305,11 @@ const EarlySecurityChecks = ({ deviceModelId, genuineCheckError, getLatestAvailableFirmwareError, - lockedDeviceModalIsOpen, + disconnectedDeviceModalIsOpen, notGenuineIsOpen, productName, resetGenuineCheckState, + history, ]); return ( diff --git a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/SeedStep.tsx b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/SeedStep.tsx index a24794d6c95b..6ad4cf099d2c 100644 --- a/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/SeedStep.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/SyncOnboarding/Manual/SeedStep.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { Divider, Flex, VerticalTimeline } from "@ledgerhq/react-ui"; -import { useTranslation } from "react-i18next"; +import { Divider, Flex, VerticalTimeline, Text } from "@ledgerhq/react-ui"; +import { useTranslation, Trans } from "react-i18next"; import { StepText } from "./shared"; import ContinueOnDeviceWithAnim from "./ContinueOnDeviceWithAnim"; import { DeviceModelId } from "@ledgerhq/types-devices"; @@ -26,11 +26,26 @@ const SeedStep = ({ seedPathStatus, deviceModelId }: Props) => { {seedPathStatus === "new_seed" ? ( + {/* @ts-expect-error weird props issue with React 18 */} - {t("syncOnboarding.manual.seedContent.newSeedDescription", { + {t("syncOnboarding.manual.seedContent.newSeedDescription1", { productName, })} + {/* @ts-expect-error weird props issue with React 18 */} + + + + {""} + + + + {/* @ts-expect-error weird props issue with React 18 */} + {t("syncOnboarding.manual.seedContent.newSeedDescription3")} + {/* @ts-expect-error weird props issue with React 18 */} + {t("syncOnboarding.manual.seedContent.newSeedDescription4")} + {/* @ts-expect-error weird props issue with React 18 */} + {t("syncOnboarding.manual.seedContent.newSeedDescription5")} { ) : seedPathStatus === "choice_restore_direct_or_recover" ? ( + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.restoreChoiceSRPTitle")} + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.restoreChoiceSRPDescription")} + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.restoreChoiceRecoverTitle")} + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.restoreChoiceRecoverDescription")} @@ -60,21 +79,46 @@ const SeedStep = ({ seedPathStatus, deviceModelId }: Props) => { ) : seedPathStatus === "restore_seed" ? ( <> + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.restoreSeed", { productName })} ) : seedPathStatus === "recover_seed" ? ( + // @ts-expect-error props issue with React 18 {t("syncOnboarding.manual.seedContent.recoverSeed")} ) : ( + {/* @ts-expect-error weird props issue with React 18 */} {t("syncOnboarding.manual.seedContent.selection", { productName, })} + {/* @ts-expect-error weird props issue with React 18 */} + + + + {""} + + + + {/* @ts-expect-error weird props issue with React 18 */} + + + + {""} + + + = ({ category={`Set up ${productName}: Step 1 device paired`} flow={analyticsFlowName} /> + {/* @ts-expect-error StepText weird children prop issue */} - {t("syncOnboarding.manual.pairedContent.description", { - deviceName: productName, - })} + { + t("syncOnboarding.manual.pairedContent.description", { + deviceName: productName, + }) as string + } + {/* @ts-expect-error StepText weird children prop issue */} - {t("syncOnboarding.manual.pairedContent.text", { + {t("syncOnboarding.manual.pairedContent.description", { deviceName: productName, })} @@ -157,11 +161,11 @@ const SyncOnboardingCompanion: React.FC = ({ renderBody: () => ( + {/* @ts-expect-error StepText weird children prop issue */} {t("syncOnboarding.manual.pinContent.description")} + {/* @ts-expect-error StepText weird children prop issue */} - {t("syncOnboarding.manual.pinContent.text", { - deviceName: productName, - })} + {t("syncOnboarding.manual.pinContent.description", { productName })} = ({ { key: StepKey.Applications, status: "inactive", - title: t("syncOnboarding.manual.installApplications.title"), + title: t("syncOnboarding.manual.installApplications.title", { productName }), renderBody: () => ( = ({ onClose, lastKnownDeviceId }) const theme = useTheme(); const handleFixClicked = useCallback(() => { - history.push("/USBTroubleshooting"); + history.replace("/USBTroubleshooting"); track("button_clicked", { button: "fix it", page: "drawer troubleshoot USB connection", diff --git a/apps/ledger-live-desktop/src/renderer/components/TabBar.tsx b/apps/ledger-live-desktop/src/renderer/components/TabBar.tsx index f1514983a30c..b0dd428f6e27 100644 --- a/apps/ledger-live-desktop/src/renderer/components/TabBar.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/TabBar.tsx @@ -113,7 +113,7 @@ const TabBar = ({ setMounted(true); }, []); const updateIndex = useCallback( - j => { + (j: number) => { setIndex(j); onIndexChange(j); }, diff --git a/apps/ledger-live-desktop/src/renderer/components/ToastOverlay/Toast.tsx b/apps/ledger-live-desktop/src/renderer/components/ToastOverlay/Toast.tsx index 419f3250866a..7704d92fa520 100644 --- a/apps/ledger-live-desktop/src/renderer/components/ToastOverlay/Toast.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/ToastOverlay/Toast.tsx @@ -118,7 +118,7 @@ export function Toast({ scheduledDismiss(duration); } }, [duration, id, onDismiss]); - const onClick = useCallback( + const onClick: React.MouseEventHandler = useCallback( event => { if (typeof callback === "function") { callback(); diff --git a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/PlatformAPIWebview.tsx b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/PlatformAPIWebview.tsx index 8e1930578690..0d2bbab553b1 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/PlatformAPIWebview.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/PlatformAPIWebview.tsx @@ -296,7 +296,7 @@ export const PlatformAPIWebview = forwardRef( const [receive] = useJSONRPCServer(handlers, handleSend); const handleMessage = useCallback( - event => { + (event: Electron.IpcMessageEvent) => { if (event.channel === "webviewToParent") { receive(JSON.parse(event.args[0])); } diff --git a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx index b66eb5cdeb45..74c52a63cbfd 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/WalletAPIWebview.tsx @@ -200,7 +200,10 @@ const useGetUserId = () => { return userId; }; -function useWebView({ manifest }: Pick, webviewRef: RefObject) { +function useWebView( + { manifest, customHandlers }: Pick, + webviewRef: RefObject, +) { const accounts = useSelector(flattenAccountsSelector); const uiHook = useUiHook(manifest); @@ -234,10 +237,11 @@ function useWebView({ manifest }: Pick, webviewRef: RefObject config, webviewHook, uiHook, + customHandlers, }); const handleMessage = useCallback( - event => { + (event: Electron.IpcMessageEvent) => { if (event.channel === "webviewToParent") { onMessage(event.args[0]); } @@ -293,13 +297,8 @@ function useWebView({ manifest }: Pick, webviewRef: RefObject return { webviewRef, widgetLoaded, onReload, webviewStyle }; } -interface Props { - manifest: AppManifest; - inputs?: Record; -} - export const WalletAPIWebview = forwardRef( - ({ manifest, inputs = {}, onStateChange }, ref) => { + ({ manifest, inputs = {}, customHandlers, onStateChange }, ref) => { const { webviewState, webviewRef, webviewProps, handleRefresh } = useWebviewState( { manifest, inputs }, ref, @@ -313,6 +312,7 @@ export const WalletAPIWebview = forwardRef( const { webviewStyle, widgetLoaded } = useWebView( { manifest, + customHandlers, }, webviewRef, ); diff --git a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/index.tsx b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/index.tsx index a275d66238f9..ce0849cff061 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/index.tsx @@ -9,7 +9,7 @@ import TrackPage from "~/renderer/analytics/TrackPage"; import { WebviewAPI, WebviewProps } from "./types"; export const Web3AppWebview = forwardRef( - ({ manifest, inputs, onStateChange }, ref) => { + ({ manifest, inputs, customHandlers, onStateChange }, ref) => { ; if (semver.satisfies(WALLET_API_VERSION, manifest.apiVersion)) { @@ -17,6 +17,7 @@ export const Web3AppWebview = forwardRef( diff --git a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/types.ts b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/types.ts index 38924db8d365..6b117b8df6c9 100644 --- a/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/types.ts +++ b/apps/ledger-live-desktop/src/renderer/components/Web3AppWebview/types.ts @@ -1,4 +1,5 @@ import { LiveAppManifest } from "@ledgerhq/live-common/platform/types"; +import { WalletAPICustomHandlers } from "@ledgerhq/live-common/wallet-api/types"; import { WebContents } from "electron"; export interface WebviewTag extends Electron.WebviewTag { @@ -10,6 +11,7 @@ export type WebviewProps = { manifest: LiveAppManifest; inputs?: Record; onStateChange?: (webviewState: WebviewState) => void; + customHandlers?: WalletAPICustomHandlers; }; export type WebviewState = { diff --git a/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/index.tsx b/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/index.tsx index 6d6242169528..e7406af2b75c 100644 --- a/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/WebPlatformPlayer/index.tsx @@ -1,5 +1,7 @@ -import React, { useRef, useState } from "react"; +import React, { useMemo, useRef, useState } from "react"; import styled from "styled-components"; +import { WalletAPICustomHandlers } from "@ledgerhq/live-common/wallet-api/types"; +import { handlers as loggerHandlers } from "@ledgerhq/live-common/wallet-api/CustomLogger/server"; import { Web3AppWebview } from "../Web3AppWebview"; import { TopBar, TopBarConfig } from "./TopBar"; import Box from "../Box"; @@ -32,6 +34,12 @@ export default function WebPlatformPlayer({ manifest, inputs, onClose, config }: const webviewAPIRef = useRef(null); const [webviewState, setWebviewState] = useState(initialWebviewState); + const customHandlers = useMemo(() => { + return { + ...loggerHandlers, + }; + }, []); + return ( @@ -47,6 +55,7 @@ export default function WebPlatformPlayer({ manifest, inputs, onClose, config }: inputs={inputs} onStateChange={setWebviewState} ref={webviewAPIRef} + customHandlers={customHandlers} /> diff --git a/apps/ledger-live-desktop/src/renderer/components/debug/DebugMock.tsx b/apps/ledger-live-desktop/src/renderer/components/debug/DebugMock.tsx index 70b8009038bb..b9b179f1914f 100644 --- a/apps/ledger-live-desktop/src/renderer/components/debug/DebugMock.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/debug/DebugMock.tsx @@ -401,14 +401,14 @@ const DebugMock = () => { ); const toggleExpandedNotif = useCallback(() => setExpandedNotif(!expandedNotif), [expandedNotif]); const queueEvent = useCallback( - event => { + (event: RawEvents) => { setQueue([...queue, event]); window.mock.events.mockDeviceEvent(event); }, [queue, setQueue], ); const unQueueEventByIndex = useCallback( - i => { + (i: number) => { window.mock.events.queue.splice(i, 1); setQueue(window.mock.events.queue); }, @@ -465,9 +465,11 @@ const DebugMock = () => { notifLiveCommonVersions, updateCache, ]); + const setValue = useCallback( - setter => (evt: React.ChangeEvent) => - setter(evt.target.value), + (setter: (value: string) => void) => + (evt: React.ChangeEvent) => + setter(evt.target.value), [], ); return ( diff --git a/apps/ledger-live-desktop/src/renderer/components/debug/DebugTheme.tsx b/apps/ledger-live-desktop/src/renderer/components/debug/DebugTheme.tsx index f36f423e8a55..5cf08f5d48fa 100644 --- a/apps/ledger-live-desktop/src/renderer/components/debug/DebugTheme.tsx +++ b/apps/ledger-live-desktop/src/renderer/components/debug/DebugTheme.tsx @@ -15,7 +15,7 @@ const Item = styled.div` const DebugTheme = () => { const dispatch = useDispatch(); const handleChangeTheme = useCallback( - theme => { + (theme: string) => { dispatch(setTheme(theme)); }, [dispatch], diff --git a/apps/ledger-live-desktop/src/renderer/components/debug/shared.ts b/apps/ledger-live-desktop/src/renderer/components/debug/shared.ts index 3fa35dd3238b..8a5c6c339729 100644 --- a/apps/ledger-live-desktop/src/renderer/components/debug/shared.ts +++ b/apps/ledger-live-desktop/src/renderer/components/debug/shared.ts @@ -1,13 +1,19 @@ import styled, { createGlobalStyle } from "styled-components"; import Text from "~/renderer/components/Text"; import { rgba } from "~/renderer/styles/helpers"; + +// For playwright, we need to disable all animations and transitions that could make the tests flaky const MockedGlobalStyle = createGlobalStyle` *, :before, :after { caret-color: transparent !important; transition-property: none !important; animation: none !important; } + ::-webkit-scrollbar { + display: none; + } `; + const Item = styled(Text)` color: white; padding: 5px; diff --git a/apps/ledger-live-desktop/src/renderer/drawers/DataSelector/SelectAccountAndCurrencyDrawer.tsx b/apps/ledger-live-desktop/src/renderer/drawers/DataSelector/SelectAccountAndCurrencyDrawer.tsx index 230c9ec866af..744471765882 100644 --- a/apps/ledger-live-desktop/src/renderer/drawers/DataSelector/SelectAccountAndCurrencyDrawer.tsx +++ b/apps/ledger-live-desktop/src/renderer/drawers/DataSelector/SelectAccountAndCurrencyDrawer.tsx @@ -75,7 +75,7 @@ function SelectAccountAndCurrencyDrawer(props: SelectAccountAndCurrencyDrawerPro return fuzzySearch(sortedCurrencies, searchValue); }, [searchValue, sortedCurrencies]); const handleCurrencySelected = useCallback( - currency => { + (currency: CryptoOrTokenCurrency) => { setDrawer( SelectAccountDrawer, { @@ -126,6 +126,7 @@ function SelectAccountAndCurrencyDrawer(props: SelectAccountAndCurrencyDrawerPro onChange={setSearchValue} /> + {/* @ts-expect-error compatibility issue betwenn CryptoOrTokenCurrency and Currency (which includes Fiat) and the SelectAccountDrawer components */} diff --git a/apps/ledger-live-desktop/src/renderer/drawers/Drawer.tsx b/apps/ledger-live-desktop/src/renderer/drawers/Drawer.tsx index cbf05364e311..31bdeddc7daf 100644 --- a/apps/ledger-live-desktop/src/renderer/drawers/Drawer.tsx +++ b/apps/ledger-live-desktop/src/renderer/drawers/Drawer.tsx @@ -18,11 +18,11 @@ const transitionStyles = { }, }; const DURATION = 200; -const Bar = styled.div.attrs<{ state: TransitionStatus }>(props => ({ +const Bar = styled.div.attrs<{ state: TransitionStatus; withPaddingTop: boolean }>(props => ({ style: { ...transitionStyles[props.state as keyof typeof transitionStyles], }, -}))<{ state: TransitionStatus; index: number }>` +}))<{ state: TransitionStatus; index: number; withPaddingTop: boolean }>` position: absolute; top: 0; left: 0; @@ -30,11 +30,13 @@ const Bar = styled.div.attrs<{ state: TransitionStatus }>(props => ({ height: 100%; z-index: ${p => p.index}; transform: translateX(${p => (p.index === 0 ? 0 : 100)}%); - transition: all ${DURATION}ms ease-in-out; + transition: + all ${DURATION}ms ease-in-out, + padding none; will-change: transform; background-color: ${p => p.theme.colors.palette.background.paper}; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.03); - padding: 62px 0px 15px 0px; + padding: ${p => (p.withPaddingTop ? "62px 0px 15px 0px" : "0px 0px 15px 0px")}; overflow-x: hidden; overflow-y: auto; `; @@ -83,7 +85,13 @@ export const Drawer = () => { key={index} > {s => ( - + {Component && ( { + (account: Account | SubAccount) => { const parentAccount = account.type !== "Account" ? accounts.find(a => a.id === account.parentId) : null; const mainAccount = getMainAccount(account, parentAccount); diff --git a/apps/ledger-live-desktop/src/renderer/env.ts b/apps/ledger-live-desktop/src/renderer/env.ts new file mode 100644 index 000000000000..6250c63262f6 --- /dev/null +++ b/apps/ledger-live-desktop/src/renderer/env.ts @@ -0,0 +1,4 @@ +process.env = { + ...process.env, + NODE_ENV: (process.env || {}).NODE_ENV || "production", +}; diff --git a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/Body.tsx index 94a855ff6f38..037580e3a824 100644 --- a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/Body.tsx @@ -97,7 +97,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("assets"); diff --git a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/fields/AsaSelector.tsx b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/fields/AsaSelector.tsx index 6a8d3f358755..ee9a5ec4c8f2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/fields/AsaSelector.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/fields/AsaSelector.tsx @@ -56,7 +56,7 @@ export default function DelegationSelectorField({ }: { account: AlgorandAccount; transaction: Transaction; - onChange: (token: TokenCurrency | undefined | null) => void; + onChange: (token?: TokenCurrency | null) => void; t: TFunction; }) { const [query, setQuery] = useState(""); diff --git a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/steps/StepAsset.tsx b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/steps/StepAsset.tsx index 7e534baf0894..f06fb156250c 100644 --- a/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/steps/StepAsset.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/algorand/OptInFlowModal/steps/StepAsset.tsx @@ -2,6 +2,7 @@ import invariant from "invariant"; import React, { useCallback } from "react"; import { Trans } from "react-i18next"; import { StepProps } from "../types"; +import { TokenCurrency } from "@ledgerhq/types-cryptoassets"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import TrackPage from "~/renderer/analytics/TrackPage"; import Box from "~/renderer/components/Box"; @@ -21,7 +22,10 @@ export default function StepAsset({ invariant(account && transaction, "account and transaction required"); const bridge = getAccountBridge(account); const onUpdateAsset = useCallback( - ({ id: assetId }) => { + (t?: TokenCurrency | null) => { + // NOTE: to match the signature of AsaSelector, i had to change a bit the function + if (!t) return; + const { id: assetId } = t; onUpdateTransaction(transaction => bridge.updateTransaction(transaction, { assetId, diff --git a/apps/ledger-live-desktop/src/renderer/families/algorand/Rewards/ClaimRewardsFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/algorand/Rewards/ClaimRewardsFlowModal/Body.tsx index 7faca0150a41..a4c425a7c93b 100644 --- a/apps/ledger-live-desktop/src/renderer/families/algorand/Rewards/ClaimRewardsFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/algorand/Rewards/ClaimRewardsFlowModal/Body.tsx @@ -98,7 +98,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/bitcoin/FullNode/steps/StepAccounts.tsx b/apps/ledger-live-desktop/src/renderer/families/bitcoin/FullNode/steps/StepAccounts.tsx index cb6ce3da0796..46821b346af4 100644 --- a/apps/ledger-live-desktop/src/renderer/families/bitcoin/FullNode/steps/StepAccounts.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/bitcoin/FullNode/steps/StepAccounts.tsx @@ -38,7 +38,7 @@ const Accounts = ({ const currency = getCryptoCurrencyById("bitcoin"); const bitcoinAccounts = accounts.filter(a => getAccountCurrency(a) === currency); const onUpdateNumberOfAccountsToScan = useCallback( - value => { + (value: string) => { if (value) { let newNumberOfAccounts = parseInt(value, 10) || 1; if ( diff --git a/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx b/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx index b22d1d14756d..49f061f15218 100644 --- a/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/bitcoin/SendAmountFields.tsx @@ -7,7 +7,7 @@ import styled from "styled-components"; import { track } from "~/renderer/analytics/segment"; import Box from "~/renderer/components/Box"; import Button from "~/renderer/components/Button"; -import SelectFeeStrategy from "~/renderer/components/SelectFeeStrategy"; +import SelectFeeStrategy, { OnClickType } from "~/renderer/components/SelectFeeStrategy"; import SendFeeMode from "~/renderer/components/SendFeeMode"; import Text from "~/renderer/components/Text"; import Tooltip from "~/renderer/components/Tooltip"; @@ -58,7 +58,7 @@ const Fields: Props = ({ }, []); // eslint-disable-line react-hooks/exhaustive-deps const onFeeStrategyClick = useCallback( - ({ amount, feesStrategy }) => { + ({ amount, feesStrategy }: OnClickType) => { track("button_clicked", { ...trackProperties, button: feesStrategy, @@ -76,7 +76,7 @@ const Fields: Props = ({ [updateTransaction, bridge], ); const setAdvanceModeAndTrack = useCallback( - state => { + (state: boolean) => { track("button_clicked", { ...trackProperties, button: state ? "advanced" : "standard", @@ -86,7 +86,7 @@ const Fields: Props = ({ [trackProperties], ); const onChangeAndTrack = useCallback( - params => { + (params: Transaction) => { track("button_clicked", { ...trackProperties, button: "fees", @@ -137,6 +137,7 @@ const Fields: Props = ({ { }} > - {t("delegation.delegationEarn")} + {t("delegation.delegationEarn", { + name: account.currency.name, + })} { closeModal(name); }, [closeModal, name]); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validator"); diff --git a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorField.tsx b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorField.tsx index 8eee002d2e9d..0db6b3096c78 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorField.tsx @@ -30,17 +30,21 @@ type Props = { const ValidatorField = ({ account, delegation, onChangeValidator, selectedPoolId }: Props) => { const [ledgerPools, setLedgerPools] = useState>([]); const unit = getAccountUnit(account); + const [showAll, setShowAll] = useState( LEDGER_POOL_IDS.length === 0 || (LEDGER_POOL_IDS.length === 1 && delegation?.poolId === LEDGER_POOL_IDS[0]), ); + const [ledgerPoolsLoading, setLedgerPoolsLoading] = useState(false); const { pools, searchQuery, setSearchQuery, onScrollEndReached, isSearching, isPaginating } = useCardanoFamilyPools(account.currency); + const poolIdsToFilterFromAllPools = [...LEDGER_POOL_IDS]; if (delegation?.poolId) { poolIdsToFilterFromAllPools.push(delegation?.poolId); } + useEffect(() => { if (LEDGER_POOL_IDS.length) { setLedgerPoolsLoading(true); @@ -60,7 +64,10 @@ const ValidatorField = ({ account, delegation, onChangeValidator, selectedPoolId } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const onSearch = useCallback(evt => setSearchQuery(evt.target.value), [setSearchQuery]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearchQuery(evt.target.value), + [setSearchQuery], + ); const renderItem = (validator: StakePool, validatorIdx: number) => { return ( + /> ); }; + return ( <> {showAll && } diff --git a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorRow.tsx b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorRow.tsx index 2dfa39f98aff..fc59867b7e37 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorRow.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/fields/ValidatorRow.tsx @@ -1,8 +1,6 @@ import { formatCurrencyUnit } from "@ledgerhq/live-common/currencies/index"; import { getDefaultExplorerView, getStakePoolExplorer } from "@ledgerhq/live-common/explorers"; import { CryptoCurrency, Unit } from "@ledgerhq/types-cryptoassets"; -import { useSelector } from "react-redux"; -import { useDiscreetMode } from "~/renderer/components/Discreet"; import { BigNumber } from "bignumber.js"; import React, { useCallback } from "react"; import { Trans } from "react-i18next"; @@ -14,7 +12,6 @@ import Check from "~/renderer/icons/Check"; import { openURL } from "~/renderer/linking"; import LedgerPoolIcon from "../LedgerPoolIcon"; import { StakePool } from "@ledgerhq/live-common/families/cardano/api/api-types"; -import { localeSelector } from "~/renderer/reducers/settings"; type Props = { currency: CryptoCurrency; @@ -25,8 +22,6 @@ type Props = { }; function CardanoPoolRow({ pool, active, onClick, unit, currency }: Props) { - const discreet = useDiscreetMode(); - const locale = useSelector(localeSelector); const explorerView = getDefaultExplorerView(currency); const onExternalLink = useCallback( (poolId: string) => { @@ -35,14 +30,7 @@ function CardanoPoolRow({ pool, active, onClick, unit, currency }: Props) { }, [explorerView], ); - const formatConfig = { - disableRounding: true, - alwaysShowSign: false, - showCode: true, - discreet, - locale, - }; - const poolCost = formatCurrencyUnit(unit, new BigNumber(pool.cost), formatConfig); + return ( onClick(pool)} @@ -89,14 +77,12 @@ function CardanoPoolRow({ pool, active, onClick, unit, currency }: Props) { {`${pool.margin} %`} - - {poolCost} - } > ); } + const StyledValidatorRow = styled(ValidatorRow)` border-color: transparent; margin-bottom: 0; diff --git a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/steps/StepDelegation.tsx b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/steps/StepDelegation.tsx index 4c5fee11dbe3..2d316aa066b2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/steps/StepDelegation.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cardano/DelegationFlowModal/steps/StepDelegation.tsx @@ -28,6 +28,7 @@ export default function StepDelegation({ const { cardanoResources } = account; invariant(cardanoResources, "cardanoResources required"); const delegation = cardanoResources.delegation; + const selectPool = (stakePool: StakePool) => { setSelectedPool(stakePool); const bridge: AccountBridge = getAccountBridge(account); @@ -39,7 +40,9 @@ export default function StepDelegation({ return updatedTransaction; }); }; + const selectedPoolId = (transaction as CardanoTransaction).poolId; + return ( @@ -68,6 +71,7 @@ export function StepDelegationFooter({ const { errors } = status; const canNext = !bridgePending && !errors.amount && transaction; const displayError = errors.amount?.message === "CardanoNotEnoughFunds" ? errors.amount : ""; + return ( {displayError ? ( diff --git a/apps/ledger-live-desktop/src/renderer/families/cardano/MemoValueField.tsx b/apps/ledger-live-desktop/src/renderer/families/cardano/MemoValueField.tsx index bf6a9865662c..2ee6bf0fbd6b 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cardano/MemoValueField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cardano/MemoValueField.tsx @@ -26,7 +26,7 @@ const MemoValueField = ({ invariant(transaction.family === "cardano", "Memo: cardano family expected"); const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memo => { + (memo: string) => { track("button_clicked", { ...trackProperties, button: "input", diff --git a/apps/ledger-live-desktop/src/renderer/families/cardano/UndelegateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cardano/UndelegateFlowModal/Body.tsx index 65ab0db8ba0d..ea1551d18412 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cardano/UndelegateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cardano/UndelegateFlowModal/Body.tsx @@ -112,7 +112,7 @@ const Body = ({ const handleCloseModal = useCallback(() => { closeModal(name); }, [closeModal, name]); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("summary"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/ManageDropDown.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/ManageDropDown.tsx index 29f8ac800281..472dd42c3b68 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/ManageDropDown.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/ManageDropDown.tsx @@ -38,6 +38,7 @@ const ManageDropDown = ({ onSelect: (action: DropDownItemType) => void; }) => { return ( + // @ts-expect-error cannot fix renderItem correctly... {() => { return ( diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/Row.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/Row.tsx index 1a8e2a9f2f1e..b24e57a6dcf3 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/AccountBodyHeader/Row.tsx @@ -22,6 +22,7 @@ import IconInfoCircle from "~/renderer/icons/InfoCircle"; import * as S from "./Row.styles"; import ManageDropDown from "./ManageDropDown"; import { ModalActions } from "../modals"; +import { DropDownItemType } from "~/renderer/components/DropDownSelector"; const voteActions = (vote: CeloVote): Array<{ key: ModalActions; label: React.ReactNode }> => { const actions: Array<{ key: ModalActions; label: React.ReactNode }> = []; if (vote.activatable) @@ -44,8 +45,8 @@ type Props = { }; export const Row = ({ account, vote, onManageAction, onExternalLink }: Props) => { const onSelect = useCallback( - action => { - onManageAction(vote, action.key); + (action: DropDownItemType) => { + onManageAction(vote, action?.key as ModalActions); }, [onManageAction, vote], ); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/ActivateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/ActivateFlowModal/Body.tsx index 5ee46cf82a35..b896c184e571 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/ActivateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/ActivateFlowModal/Body.tsx @@ -92,7 +92,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }, ); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { onChangeStepId("vote"); }, [onChangeStepId]); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/LockFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/LockFlowModal/Body.tsx index d4e08c1526f8..1f59d4108759 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/LockFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/LockFlowModal/Body.tsx @@ -89,7 +89,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }, ); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("amount"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/ManageModal/ManageModal.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/ManageModal/ManageModal.tsx index 0a5f772b0f10..b30295ba8cc9 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/ManageModal/ManageModal.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/ManageModal/ManageModal.tsx @@ -17,6 +17,7 @@ import { } from "@ledgerhq/live-common/families/celo/logic"; import * as S from "./ManageModal.styles"; import { CeloAccount } from "@ledgerhq/live-common/families/celo/types"; +import { ModalData } from "~/renderer/modals/types"; export type Props = { account: CeloAccount; @@ -29,7 +30,7 @@ const ManageModal = ({ account, source, ...rest }: Props) => { invariant(celoResources, "celo account expected"); const dispatch = useDispatch(); const onSelectAction = useCallback( - (onClose, name, params = {}) => { + (onClose: () => void, name: keyof ModalData, params = {}) => { onClose(); dispatch( openModal(name, { diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/RevokeFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/RevokeFlowModal/Body.tsx index cc31f7316873..33c5edb8fa89 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/RevokeFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/RevokeFlowModal/Body.tsx @@ -112,7 +112,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/SimpleOperationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/SimpleOperationFlowModal/Body.tsx index 313750d0ab61..cded3eb123cf 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/SimpleOperationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/SimpleOperationFlowModal/Body.tsx @@ -107,7 +107,7 @@ const Body = ({ t, stepId, device, openModal, onClose, onChangeStepId, params, m }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/UnlockFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/UnlockFlowModal/Body.tsx index d2d965609b2a..e276abdb3026 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/UnlockFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/UnlockFlowModal/Body.tsx @@ -94,7 +94,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("amount"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/Body.tsx index 8704dc2a41f8..1c8e0573684c 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/Body.tsx @@ -106,7 +106,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/fields/ValidatorGroupsField.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/fields/ValidatorGroupsField.tsx index e2aa77968b78..ab9f6f30aa8b 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/fields/ValidatorGroupsField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/VoteFlowModal/fields/ValidatorGroupsField.tsx @@ -34,7 +34,10 @@ const ValidatorGroupsField = ({ const [showAll, setShowAll] = useState(false); const unit = getAccountUnit(account); const validatorGroups = useValidatorGroups(search); - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); const chosenValidatorGroup = useMemo(() => { if (chosenValidatorGroupAddress !== null) { return validatorGroups.find(v => v.address === chosenValidatorGroupAddress); diff --git a/apps/ledger-live-desktop/src/renderer/families/celo/WithdrawFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/celo/WithdrawFlowModal/Body.tsx index d91065739d2e..9a5d134affec 100644 --- a/apps/ledger-live-desktop/src/renderer/families/celo/WithdrawFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/celo/WithdrawFlowModal/Body.tsx @@ -95,7 +95,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { onChangeStepId("amount"); }, [onChangeStepId]); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx index 158bef7f0df1..16dddd1dbdca 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/Body.tsx @@ -110,7 +110,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("claimRewards"); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx index e2d5e444ce6c..5457f858c9f2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/fields/ModeSelectorField.tsx @@ -5,6 +5,7 @@ import ToggleButton from "~/renderer/components/ToggleButton"; import InfoCircle from "~/renderer/icons/InfoCircle"; import Text from "~/renderer/components/Text"; import Popover from "~/renderer/components/Popover"; +import { CosmosLikeTransaction } from "@ledgerhq/live-common/families/cosmos/types"; const options = [ { value: "claimRewardCompound", @@ -19,7 +20,7 @@ export default function ModeSelectorField({ mode, onChange, }: { - mode: string; + mode: CosmosLikeTransaction["mode"]; onChange: (r: string) => void; }) { return ( diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx index cd1f5fbdcd13..339c04c983bf 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/ClaimRewardsFlowModal/steps/StepClaimRewards.tsx @@ -15,6 +15,11 @@ import Text from "~/renderer/components/Text"; import DelegationSelectorField from "../fields/DelegationSelectorField"; import ErrorBanner from "~/renderer/components/ErrorBanner"; import AccountFooter from "~/renderer/modals/Send/AccountFooter"; +import { + CosmosLikeTransaction, + CosmosMappedDelegation, +} from "@ledgerhq/live-common/families/cosmos/types"; + export default function StepClaimRewards({ account, parentAccount, @@ -29,16 +34,16 @@ export default function StepClaimRewards({ const bridge = getAccountBridge(account, parentAccount); const unit = getAccountUnit(account); const updateClaimRewards = useCallback( - newTransaction => { + (newTransaction: Partial) => { onUpdateTransaction(transaction => bridge.updateTransaction(transaction, newTransaction)); }, [bridge, onUpdateTransaction], ); const onChangeMode = useCallback( - mode => { + (mode: string) => { updateClaimRewards({ ...transaction, - mode, + mode: mode as CosmosLikeTransaction["mode"], }); }, [updateClaimRewards, transaction], @@ -53,7 +58,7 @@ export default function StepClaimRewards({ locale, }); const onDelegationChange = useCallback( - ({ validatorAddress, pendingRewards }) => { + ({ validatorAddress, pendingRewards }: CosmosMappedDelegation) => { updateClaimRewards({ ...transaction, validators: [ @@ -96,6 +101,7 @@ export default function StepClaimRewards({ transaction={transaction} account={account} t={t} + // @ts-expect-error the underlying select can accept null and undefined onChange={onDelegationChange} /> diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/Row.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/Row.tsx index 30b839d737e3..853d36e7dca6 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/Delegation/Row.tsx @@ -112,8 +112,8 @@ export function Row({ onExternalLink, }: Props) { const onSelect = useCallback( - action => { - onManageAction(validatorAddress, action.key); + (action: (typeof dropDownItems)[number]) => { + onManageAction(validatorAddress, action.key as DelegationActionsModalName); }, [onManageAction, validatorAddress], ); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx index 617de3902c75..178382230082 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/Body.tsx @@ -116,7 +116,7 @@ const Body = ({ onClose, t, stepId, device, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validator"); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/fields/ValidatorField.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/fields/ValidatorField.tsx index f208161ef85d..6f0c1e70887f 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/fields/ValidatorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/DelegationFlowModal/fields/ValidatorField.tsx @@ -30,7 +30,10 @@ const ValidatorField = ({ account, onChangeValidator, chosenVoteAccAddr }: Props const unit = getAccountUnit(account); const currencyId = account.currency.id; const validators = useLedgerFirstShuffledValidatorsCosmosFamily(currencyId, search); - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); const chosenValidator = useMemo(() => { return [validators.find(v => v.validatorAddress === chosenVoteAccAddr) || validators[0]]; }, [validators, chosenVoteAccAddr]); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/MemoValueField.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/MemoValueField.tsx index 8e401e39179c..756f694248d6 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/MemoValueField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/MemoValueField.tsx @@ -23,7 +23,7 @@ const MemoValueField = ({ invariant(transaction.family === "cosmos", "MemoTypeField: cosmos family expected"); const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memo => { + (memo: string) => { onChange( bridge.updateTransaction(transaction, { memo, diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/Body.tsx index d9ca58b307cf..5eacdea028cb 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/Body.tsx @@ -126,7 +126,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validators"); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/fields/ValidatorField.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/fields/ValidatorField.tsx index d7127e1ee647..832e9e915a7e 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/fields/ValidatorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/fields/ValidatorField.tsx @@ -26,13 +26,16 @@ export default function ValidatorField({ }: { account: CosmosAccount; transaction: Transaction; - onChange: (a?: { address: string } | null) => void; + onChange: (a: { address: string }) => void; }) { const currencyId = account.currency.id.toLowerCase(); const [search, setSearch] = useState(""); const validators = useLedgerFirstShuffledValidatorsCosmosFamily(currencyId, search); const { cosmosResources } = account; - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); invariant(cosmosResources, "cosmosResources required"); const unit = getAccountUnit(account); const fromValidatorAddress = transaction.sourceValidator; diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepDestinationValidators.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepDestinationValidators.tsx index 7b685a143994..e3518e9ce96a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepDestinationValidators.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepDestinationValidators.tsx @@ -4,6 +4,7 @@ import { BigNumber } from "bignumber.js"; import { StepProps } from "../types"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import ValidatorField from "../fields/ValidatorField"; +import { Transaction } from "@ledgerhq/live-common/families/cosmos/types"; export default function StepValidators({ account, parentAccount, @@ -14,13 +15,14 @@ export default function StepValidators({ invariant(account && account.cosmosResources && transaction, "account and transaction required"); const bridge = getAccountBridge(account, parentAccount); const updateRedelegation = useCallback( - newTransaction => { + (newTransaction: Partial) => { onUpdateTransaction(transaction => bridge.updateTransaction(transaction, newTransaction)); }, [bridge, onUpdateTransaction], ); + const updateDestinationValidator = useCallback( - ({ address }) => { + ({ address }: { address: string }) => { updateRedelegation({ ...transaction, validators: [ diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx index d164c21cb66c..042a42f9ff5e 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/steps/StepValidators.tsx @@ -72,7 +72,7 @@ export default function StepValidators({ return { address: found.validatorAddress, amount: found.amount }; }, [account, transaction.sourceValidator]); const updateRedelegation = useCallback( - newTransaction => { + (newTransaction: Partial>) => { onUpdateTransaction(transaction => bridge.updateTransaction(transaction, newTransaction)); }, [bridge, onUpdateTransaction], @@ -102,7 +102,7 @@ export default function StepValidators({ [updateRedelegation, transaction, account.cosmosResources], ); const onChangeAmount = useCallback( - amount => + (amount: BigNumber) => updateRedelegation({ ...transaction, validators: diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/types.ts b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/types.ts index 89ca78eeb5b0..087d8f3de7d7 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/types.ts +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/RedelegationFlowModal/types.ts @@ -26,7 +26,7 @@ export type StepProps = { optimisticOperation: Operation | undefined; error: Error | undefined; signed: boolean; - transaction: Transaction | undefined | null; + transaction?: Transaction | null; status: TransactionStatus; onChangeTransaction: (a: Transaction) => void; onUpdateTransaction: (a: (a: Transaction) => Transaction) => void; diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/Body.tsx index e24277c25649..d63708835137 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/Body.tsx @@ -11,7 +11,7 @@ import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { SyncSkipUnderPriority } from "@ledgerhq/live-common/bridge/react/index"; import useBridgeTransaction from "@ledgerhq/live-common/bridge/useBridgeTransaction"; import { Account, Operation } from "@ledgerhq/types-live"; -import { StepId } from "./types"; +import { StepId, St } from "./types"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import logger from "~/renderer/logger"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; @@ -96,7 +96,7 @@ function Body({ setTransactionError(null); onChangeStepId("amount"); }, [onChangeStepId]); - const handleStepChange = useCallback(({ id }) => onChangeStepId(id), [onChangeStepId]); + const handleStepChange = useCallback(({ id }: St) => onChangeStepId(id), [onChangeStepId]); const handleOperationBroadcasted = useCallback( (optimisticOperation: Operation) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/index.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/index.tsx index 50d763090cca..56efecf7cbf2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/index.tsx @@ -8,7 +8,7 @@ export default function UndelegationModal() { const onHide = useCallback(() => { setStepId("amount"); }, []); - const onChange = useCallback(id => { + const onChange = useCallback((id: StepId) => { setStepId(id); }, []); const isModalLocked = ["device", "confirmation"].includes(stepId); diff --git a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx index e8f6cfba7517..6e8bb353af0c 100644 --- a/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/cosmos/UndelegationFlowModal/steps/Amount.tsx @@ -4,7 +4,10 @@ import React, { useCallback, useMemo } from "react"; import { useTranslation, Trans } from "react-i18next"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { StepProps } from "../types"; -import { CosmosMappedDelegation } from "@ledgerhq/live-common/families/cosmos/types"; +import { + CosmosDelegationInfo, + CosmosMappedDelegation, +} from "@ledgerhq/live-common/families/cosmos/types"; import TrackPage from "~/renderer/analytics/TrackPage"; import Box from "~/renderer/components/Box"; import Button from "~/renderer/components/Button"; @@ -25,7 +28,7 @@ export default function StepAmount({ invariant(account && transaction && transaction.validators, "account and transaction required"); const bridge = getAccountBridge(account); const updateValidator = useCallback( - validatorFields => { + (validatorFields: Partial) => { onUpdateTransaction(tx => bridge.updateTransaction(tx, { ...tx, diff --git a/apps/ledger-live-desktop/src/renderer/families/crypto_org/MemoValueField.tsx b/apps/ledger-live-desktop/src/renderer/families/crypto_org/MemoValueField.tsx index 9bb621d12819..25e78a21fb23 100644 --- a/apps/ledger-live-desktop/src/renderer/families/crypto_org/MemoValueField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/crypto_org/MemoValueField.tsx @@ -22,7 +22,7 @@ const MemoValueField = ({ const { t } = useTranslation(); const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memo => { + (memo: string) => { onChange( bridge.updateTransaction(transaction, { memo, diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/Body.tsx index c96c7a4e7677..ab250f2a2c4a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/Body.tsx @@ -101,7 +101,7 @@ const Body = (props: Props) => { }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("claimRewards"); diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/DelegationSelectorField.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/DelegationSelectorField.tsx index 1194c43b708a..2a2352ace7fb 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/DelegationSelectorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/DelegationSelectorField.tsx @@ -10,6 +10,7 @@ import { TFunction } from "i18next"; import { AccountBridge } from "@ledgerhq/types-live"; import { DelegationType } from "~/renderer/families/elrond/types"; import { Transaction, ElrondProvider } from "@ledgerhq/live-common/families/elrond/types"; +import { Option } from "react-select/src/filters"; type NoOptionsMessageCallbackType = { inputValue: string; @@ -22,7 +23,7 @@ interface DelegationSelectorFieldType { delegations: Array; contract: string; transaction: Transaction; - onChange: (validator: ElrondProvider | undefined | null) => void; + onChange: (validator?: ElrondProvider | null) => void; onUpdateTransaction: (transaction: (_: Transaction) => Transaction) => void; t: TFunction; bridge: AccountBridge; @@ -89,7 +90,7 @@ const DelegationSelectorField = (props: DelegationSelectorFieldType) => { [t], ); const filterOptions = useCallback( - (option, needle: string): boolean => + (option: Option, needle: string): boolean => BigNumber(option.data.delegation.claimableRewards).gt(0) && option.data.identity.name ? option.data.identity.name.toLowerCase().includes(needle.toLowerCase()) : false, diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/ModeSelectorField.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/ModeSelectorField.tsx index 58ec77901fff..167235636f16 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/ModeSelectorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Claim/fields/ModeSelectorField.tsx @@ -5,9 +5,11 @@ import ToggleButton from "~/renderer/components/ToggleButton"; import InfoCircle from "~/renderer/icons/InfoCircle"; import Text from "~/renderer/components/Text"; import Popover from "~/renderer/components/Popover"; +import { ElrondTransactionMode } from "@ledgerhq/live-common/families/elrond/types"; + export interface Props { mode: string; - onChange: (mode: string) => void; + onChange: (mode: ElrondTransactionMode) => void; } const options = [ { @@ -28,7 +30,7 @@ const ModeSelectorField = (props: Props) => { }} alignSelf="center" > - + void} /> { @@ -30,13 +31,13 @@ const StepClaimRewards = (props: StepProps) => { const bridge = getAccountBridge(account); const updateClaimRewards = useCallback( - newTransaction => { + (newTransaction: Partial) => { onUpdateTransaction(transaction => bridge.updateTransaction(transaction, newTransaction)); }, [bridge, onUpdateTransaction], ); const onChangeMode = useCallback( - (mode: string) => { + (mode: ElrondTransactionMode) => { updateClaimRewards({ ...transaction, mode, @@ -45,6 +46,8 @@ const StepClaimRewards = (props: StepProps) => { [updateClaimRewards, transaction], ); const onDelegationChange = useCallback( + // @ts-expect-error the expected type should be ElrondProvider | null + // however if we do that, there is no `delegation` key on validator halp validator => { updateClaimRewards({ ...transaction, diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/Body.tsx index fd6e91356a6c..d762b9488ea2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/Body.tsx @@ -116,7 +116,7 @@ const Body = (props: Props) => { }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validator"); diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/steps/StepAmount.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/steps/StepAmount.tsx index aaaea59c459c..1cd7c1b73f4a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/steps/StepAmount.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Delegate/steps/StepAmount.tsx @@ -15,7 +15,7 @@ const StepAmount = (props: StepProps) => { const { t, account, transaction, onChangeTransaction, error, status, bridgePending } = props; const mainAccount = account ? getMainAccount(account) : null; const onUpdateTransactionCallback = useCallback( - transaction => + (transaction: NonNullable) => onChangeTransaction({ ...transaction, mode: "delegate", diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/Body.tsx index 5dcab0db3804..7f222fed1d48 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/Body.tsx @@ -22,7 +22,7 @@ import { ElrondAccount, ElrondProvider, } from "@ledgerhq/live-common/families/elrond/types"; -import { StepId } from "./types"; +import { StepId, St } from "./types"; import { Device } from "@ledgerhq/types-devices"; import { DelegationType } from "../../../types"; @@ -99,7 +99,7 @@ const Body = (props: Props) => { setTransactionError(null); onChangeStepId("amount"); }, [onChangeStepId]); - const handleStepChange = useCallback(({ id }) => onChangeStepId(id), [onChangeStepId]); + const handleStepChange = useCallback(({ id }: St) => onChangeStepId(id), [onChangeStepId]); const handleOperationBroadcasted = useCallback( (optimisticOperation: Operation) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/fields/Validator.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/fields/Validator.tsx index 349a82335ac0..09e11ef6c7b6 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/fields/Validator.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Undelegate/fields/Validator.tsx @@ -7,6 +7,7 @@ import Label from "~/renderer/components/Label"; import Select from "~/renderer/components/Select"; import Text from "~/renderer/components/Text"; import { DelegationType } from "~/renderer/families/elrond/types"; +import { Option } from "react-select/src/filters"; type NoOptionsMessageCallbackType = { inputValue: string; @@ -69,14 +70,15 @@ const Dropdown = (props: Props) => { [t], ); const filterOptions = useCallback( - (option, needle: string): boolean => + (option: Option, needle: string): boolean => option.data.validator.identity.name ? option.data.validator.identity.name.toLowerCase().includes(needle.toLowerCase()) : false, [], ); const onValueChange = useCallback( - option => { + (option?: DelegationType | null) => { + if (!option) return; setValue(option); if (onChange) { onChange(option); diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/Body.tsx index 9a415d111a27..f976ab38a655 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/Body.tsx @@ -98,7 +98,7 @@ const Body = (props: Props) => { }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("withdraw"); diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/fields/DelegationSelectorField.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/fields/DelegationSelectorField.tsx index 5984dad27798..aed282d68497 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/fields/DelegationSelectorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/fields/DelegationSelectorField.tsx @@ -10,6 +10,7 @@ import { TFunction } from "i18next"; import { AccountBridge } from "@ledgerhq/types-live"; import { ElrondProvider, Transaction } from "@ledgerhq/live-common/families/elrond/types"; import { UnbondingType } from "~/renderer/families/elrond/types"; +import { Option as FilterOption } from "react-select/src/filters"; type NoOptionsMessageCallbackType = { inputValue: string; @@ -71,13 +72,15 @@ const DelegationSelectorField = (props: Props) => { [t], ); const filterOptions = useCallback( - (option, needle: string): boolean => + (option: FilterOption, needle: string): boolean => option.data.validator.identity.name ? option.data.validator.identity.name.toLowerCase().includes(needle.toLowerCase()) : false, [], ); const onValueChange = useCallback( + // @ts-expect-error another amazing typing between this function, the one expected by Select + // and the onChange we use here... option => { setValue(option); if (onChange) { diff --git a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/steps/StepWithdraw.tsx b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/steps/StepWithdraw.tsx index 197a9241787d..04975827f890 100644 --- a/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/steps/StepWithdraw.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/elrond/components/Modals/Withdraw/steps/StepWithdraw.tsx @@ -30,6 +30,7 @@ const StepWithdraw = (props: StepProps) => { } = props; const bridge: AccountBridge = getAccountBridge(account); const onDelegationChange = useCallback( + // @ts-expect-error another TS puzzle for another day validator => { onUpdateTransaction(transaction => bridge.updateTransaction(transaction, { diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/GasPriceField.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/GasPriceField.tsx index d0b2c74f4676..e2d7623da4f0 100644 --- a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/GasPriceField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/GasPriceField.tsx @@ -4,6 +4,7 @@ import invariant from "invariant"; import React, { memo, useCallback } from "react"; import FeeSliderField from "~/renderer/components/FeeSliderField"; import { EvmFamily } from "../types"; +import BigNumber from "bignumber.js"; let lastNetworkGasPrice: Range | undefined; // local cache of last value to prevent extra blinks @@ -16,7 +17,7 @@ const FeesField: NonNullable["component"] = ({ invariant(transaction.family === "evm", "GasPriceField: evm family expected"); const bridge = getAccountBridge(account); const onGasPriceChange = useCallback( - gasPrice => { + (gasPrice: BigNumber) => { updateTransaction(transaction => bridge.updateTransaction(transaction, { gasPrice, diff --git a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx index e8d118b0c56d..eae1cf9779fb 100644 --- a/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/evm/SendAmountFields/index.tsx @@ -1,4 +1,4 @@ -import { Transaction as EvmTransaction } from "@ledgerhq/coin-evm/types/index"; +import { Transaction as EvmTransaction, Strategy } from "@ledgerhq/coin-evm/types/index"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { useGasOptions } from "@ledgerhq/live-common/families/evm/react"; import { log } from "@ledgerhq/logs"; @@ -36,7 +36,7 @@ const Root: NonNullable["component"] = props => { const shouldUseEip1559 = transaction.type === 2; const onFeeStrategyClick = useCallback( - ({ feesStrategy }) => { + ({ feesStrategy }: { feesStrategy: Strategy }) => { updateTransaction((tx: EvmTransaction) => bridge.updateTransaction(tx, { feesStrategy, @@ -53,7 +53,6 @@ const Root: NonNullable["component"] = props => { margin: "auto", }} size={32} - id="evm-fee-strategy-gas-options-spinner" /> ); } diff --git a/apps/ledger-live-desktop/src/renderer/families/near/Staking/Row.tsx b/apps/ledger-live-desktop/src/renderer/families/near/Staking/Row.tsx index 81b380abb418..21e2c73e552b 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/Staking/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/Staking/Row.tsx @@ -99,8 +99,8 @@ export function Row({ const unstakingEnabled = canUnstake(stakingPosition); const withdawingEnabled = canWithdraw(stakingPosition); const onSelect = useCallback( - action => { - onManageAction(validatorId, action.key); + (action: (typeof dropDownItems)[number]) => { + onManageAction(validatorId, action.key as "MODAL_NEAR_UNSTAKE" | "MODAL_NEAR_WITHDRAW"); }, [onManageAction, validatorId], ); diff --git a/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/Body.tsx index 845d60cc86e6..5bde42378414 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/Body.tsx @@ -97,7 +97,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validator"); diff --git a/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/fields/ValidatorField.tsx b/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/fields/ValidatorField.tsx index 5c5ba438897a..c92886e852c9 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/fields/ValidatorField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/StakingFlowModal/fields/ValidatorField.tsx @@ -37,7 +37,10 @@ const ValidatorField = ({ account, onChangeValidator, chosenVoteAccAddr }: Props /> ); }; - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); if (!chosenVoteAccAddr && validators[0].validatorAddress === FIGMENT_NEAR_VALIDATOR_ADDRESS) { onChangeValidator({ address: FIGMENT_NEAR_VALIDATOR_ADDRESS, diff --git a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/Body.tsx index 77a39b1a582b..be036c4ec761 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/Body.tsx @@ -11,7 +11,7 @@ import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { SyncSkipUnderPriority } from "@ledgerhq/live-common/bridge/react/index"; import { getMaxAmount } from "@ledgerhq/live-common/families/near/logic"; import useBridgeTransaction from "@ledgerhq/live-common/bridge/useBridgeTransaction"; -import { StepId } from "./types"; +import { St, StepId } from "./types"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import logger from "~/renderer/logger"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; @@ -100,7 +100,7 @@ function Body({ setTransactionError(null); onChangeStepId("amount"); }, [onChangeStepId]); - const handleStepChange = useCallback(({ id }) => onChangeStepId(id), [onChangeStepId]); + const handleStepChange = useCallback(({ id }: St) => onChangeStepId(id), [onChangeStepId]); const handleOperationBroadcasted = useCallback( (optimisticOperation: Operation) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/index.tsx b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/index.tsx index baa16e09d50a..7baad8c7afb2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/index.tsx @@ -8,7 +8,7 @@ export default function UnstakingModal() { const onHide = useCallback(() => { setStepId("amount"); }, []); - const onChange = useCallback(id => { + const onChange = useCallback((id: StepId) => { setStepId(id); }, []); const isModalLocked = ["device", "confirmation"].includes(stepId); diff --git a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/steps/Amount.tsx b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/steps/Amount.tsx index bf415e136317..cd7e14a5517f 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/steps/Amount.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/UnstakingFlowModal/steps/Amount.tsx @@ -23,7 +23,7 @@ export default function StepAmount({ const [staked, setStaked] = useState(transaction.amount); const bridge = getAccountBridge(account); const updateValidator = useCallback( - ({ address, amount }) => { + ({ address, amount }: { address: string; amount: BigNumber }) => { onUpdateTransaction(tx => bridge.updateTransaction(tx, { ...tx, diff --git a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/Body.tsx index c368fda4f8a0..0c1ccf049171 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/Body.tsx @@ -11,7 +11,7 @@ import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { SyncSkipUnderPriority } from "@ledgerhq/live-common/bridge/react/index"; import { getMaxAmount } from "@ledgerhq/live-common/families/near/logic"; import useBridgeTransaction from "@ledgerhq/live-common/bridge/useBridgeTransaction"; -import { StepId } from "./types"; +import { St, StepId } from "./types"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import logger from "~/renderer/logger"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; @@ -100,7 +100,7 @@ function Body({ setTransactionError(null); onChangeStepId("amount"); }, [onChangeStepId]); - const handleStepChange = useCallback(({ id }) => onChangeStepId(id), [onChangeStepId]); + const handleStepChange = useCallback(({ id }: St) => onChangeStepId(id), [onChangeStepId]); const handleOperationBroadcasted = useCallback( (optimisticOperation: Operation) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/index.tsx b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/index.tsx index ec75548367a9..89b11f5afaa0 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/index.tsx @@ -8,7 +8,7 @@ export default function WithdrawingModal() { const onHide = useCallback(() => { setStepId("amount"); }, []); - const onChange = useCallback(id => { + const onChange = useCallback((id: StepId) => { setStepId(id); }, []); const isModalLocked = ["device", "confirmation"].includes(stepId); diff --git a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/steps/Amount.tsx b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/steps/Amount.tsx index d9e9831ff1a4..f3e8971261de 100644 --- a/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/steps/Amount.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/near/WithdrawingFlowModal/steps/Amount.tsx @@ -21,7 +21,7 @@ export default function StepAmount({ const [available, setAvailable] = useState(transaction.amount); const bridge = getAccountBridge(account); const updateValidator = useCallback( - ({ address, amount }) => { + ({ address, amount }: { address: string; amount: BigNumber }) => { onUpdateTransaction(tx => bridge.updateTransaction(tx, { ...tx, diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/BondFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/BondFlowModal/Body.tsx index 035623be0c37..b8538fc59d4f 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/BondFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/BondFlowModal/Body.tsx @@ -87,7 +87,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("amount"); diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/ManageModal.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/ManageModal.tsx index 95be34d83a57..49f6568ecc93 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/ManageModal.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/ManageModal.tsx @@ -21,6 +21,7 @@ import WithdrawUnbondedIcon from "~/renderer/icons/Coins"; import Text from "~/renderer/components/Text"; import ElectionStatusWarning from "./ElectionStatusWarning"; import { PolkadotAccount } from "@ledgerhq/live-common/families/polkadot/types"; +import { ModalData } from "~/renderer/modals/types"; const IconWrapper = styled.div` width: 32px; height: 32px; @@ -104,7 +105,7 @@ const ManageModal = ({ account, source, ...rest }: Props) => { invariant(polkadotResources, "polkadot account expected"); const { unlockedBalance, nominations } = polkadotResources; const onSelectAction = useCallback( - (onClose, name, params = {}) => { + (onClose: () => void, name: keyof ModalData, params = {}) => { onClose(); dispatch( openModal(name, { diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/Nomination/index.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/Nomination/index.tsx index 7b7ac49b1f91..cd0f2dc8a5d2 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/Nomination/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/Nomination/index.tsx @@ -176,7 +176,10 @@ const Nomination = ({ account }: { account: PolkadotAccount }) => { const withdrawEnabled = !electionOpen && hasUnlockedBalance && !hasPendingWithdrawUnbondedOperation; const renderNomination = useCallback( - ({ nomination, validator }, index) => ( + ( + { nomination, validator }: { nomination: PolkadotNomination; validator?: PolkadotValidator }, + index: number, + ) => ( { [account, onExternalLink], ); const renderShowInactiveNominations = useCallback( - collapsed => ( + (collapsed: boolean) => ( { [mappedNominations], ); const renderUnlocking = useCallback( - (unlocking, index) => , + (unlocking: PolkadotUnlocking, index: number) => ( + + ), [account], ); const renderShowAllUnlockings = useCallback( - collapsed => ( + (collapsed: boolean) => ( { @@ -446,6 +452,7 @@ const Nomination = ({ account }: { account: PolkadotAccount }) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/Body.tsx index 5645237fdb25..30017e8fcddb 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/Body.tsx @@ -108,7 +108,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("castNominations"); diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorRow.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorRow.tsx index 0bb3a276d997..073824e0d348 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorRow.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorRow.tsx @@ -160,7 +160,7 @@ const ValidatorRow = ({ const commissionBN = BigNumber(commission); // FIXME: Y U NO BIGNUMBER ? const totalBN = BigNumber(totalBonded); // FIXME: Y U NO BIGNUMBER ? - const onTitleClick = useCallback( + const onTitleClick: React.MouseEventHandler = useCallback( e => { e.stopPropagation(); onExternalLink(address); diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorsField.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorsField.tsx index b7bffd1afb90..05bdefd8804b 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorsField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/fields/ValidatorsField.tsx @@ -136,7 +136,7 @@ const ValidatorField = ({ .map(nomination => nomination.address); const validatorsSelected = validators.length; const onUpdateNomination = useCallback( - (address, isSelected) => { + (address: string, isSelected: boolean) => { onChangeNominations(existing => { const update = existing.filter(v => v !== address); if (isSelected) { @@ -156,7 +156,10 @@ const ValidatorField = ({ }, [explorerView], ); - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); /** auto focus first input on mount */ useEffect(() => { diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/steps/StepNomination.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/steps/StepNomination.tsx index 24ac5090954c..cd59f998713d 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/steps/StepNomination.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/NominationFlowModal/steps/StepNomination.tsx @@ -28,11 +28,12 @@ export default function StepNomination({ }); }, [onClose, openModal, account]); const updateNomination = useCallback( - updater => { - onUpdateTransaction(transaction => - bridge?.updateTransaction(transaction, { - validators: updater(transaction.validators || []), - }), + (updater: (a: string[]) => string[]) => { + onUpdateTransaction( + transaction => + bridge?.updateTransaction(transaction, { + validators: updater(transaction.validators || []), + }), ); }, [bridge, onUpdateTransaction], diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/SimpleOperationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/SimpleOperationFlowModal/Body.tsx index 34626bed2f7c..dd1425cd5863 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/SimpleOperationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/SimpleOperationFlowModal/Body.tsx @@ -108,7 +108,7 @@ const Body = ({ t, stepId, device, openModal, onChangeStepId, params, onClose, m }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/polkadot/UnbondFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/polkadot/UnbondFlowModal/Body.tsx index 6b92f970ebff..84c2d368f75e 100644 --- a/apps/ledger-live-desktop/src/renderer/families/polkadot/UnbondFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/polkadot/UnbondFlowModal/Body.tsx @@ -87,7 +87,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("amount"); diff --git a/apps/ledger-live-desktop/src/renderer/families/ripple/SendAmountFields.tsx b/apps/ledger-live-desktop/src/renderer/families/ripple/SendAmountFields.tsx index fa3f9beb98a9..cf59f9819ecf 100644 --- a/apps/ledger-live-desktop/src/renderer/families/ripple/SendAmountFields.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/ripple/SendAmountFields.tsx @@ -9,6 +9,7 @@ import InputCurrency from "~/renderer/components/InputCurrency"; import Box from "~/renderer/components/Box"; import GenericContainer from "~/renderer/components/FeesContainer"; import { track } from "~/renderer/analytics/segment"; +import BigNumber from "bignumber.js"; type Props = { account: Account; @@ -28,7 +29,7 @@ function FeesField({ account, transaction, onChange, status, trackProperties = { invariant(transaction.family === "ripple", "FeeField: ripple family expected"); const bridge = getAccountBridge(account); const onChangeFee = useCallback( - fee => { + (fee: BigNumber) => { track("button_clicked", { ...trackProperties, fee, diff --git a/apps/ledger-live-desktop/src/renderer/families/ripple/SendRecipientFields.tsx b/apps/ledger-live-desktop/src/renderer/families/ripple/SendRecipientFields.tsx index eb14d73834cc..d191c1f527fc 100644 --- a/apps/ledger-live-desktop/src/renderer/families/ripple/SendRecipientFields.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/ripple/SendRecipientFields.tsx @@ -16,7 +16,7 @@ const uint32maxPlus1 = BigNumber(2).pow(32); const TagField = ({ onChange, account, transaction }: Props) => { const { t } = useTranslation(); const onChangeTag = useCallback( - str => { + (str: string) => { const bridge = getAccountBridge(account); const tag = BigNumber(str.replace(/[^0-9]/g, "")); const patch = { diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/Delegation/Row.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/Delegation/Row.tsx index 8f73e733fb53..54930e874bcd 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/Delegation/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/Delegation/Row.tsx @@ -92,14 +92,16 @@ type Props = { onExternalLink: (stakeWithMeta: SolanaStakeWithMeta) => void; }; export function Row({ account, stakeWithMeta, onManageAction, onExternalLink }: Props) { + const { stake, meta } = stakeWithMeta; + const stakeActions = solanaStakeActions(stake).map(toStakeDropDownItem); + const onSelect = useCallback( - action => { + (action: (typeof stakeActions)[number]) => { onManageAction(stakeWithMeta, action.key); }, [onManageAction, stakeWithMeta], ); - const { stake, meta } = stakeWithMeta; - const stakeActions = solanaStakeActions(stake).map(toStakeDropDownItem); + const validatorName = meta.validator?.name ?? stake.delegation?.voteAccAddr ?? "-"; const onExternalLinkClick = () => onExternalLink(stakeWithMeta); const formatAmount = (amount: number) => { diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationActivateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationActivateFlowModal/Body.tsx index f690df84d03a..527012cd5141 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationActivateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationActivateFlowModal/Body.tsx @@ -106,7 +106,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("validator"); diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationDeactivateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationDeactivateFlowModal/Body.tsx index 33ddc03b3412..29497f700083 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationDeactivateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationDeactivateFlowModal/Body.tsx @@ -104,7 +104,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationFlowModal/Body.tsx index be0bad614fcf..0577673baadf 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationFlowModal/Body.tsx @@ -112,7 +112,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationReactivateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationReactivateFlowModal/Body.tsx index 7844e352bb19..60f060745c96 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationReactivateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationReactivateFlowModal/Body.tsx @@ -111,7 +111,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("connectDevice"); diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationWithdrawFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationWithdrawFlowModal/Body.tsx index fcc834922c5f..1d2deac33dec 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/DelegationWithdrawFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/DelegationWithdrawFlowModal/Body.tsx @@ -112,7 +112,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("amount"); diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/MemoValueField.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/MemoValueField.tsx index 21efad94e12b..6f0b076a773d 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/MemoValueField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/MemoValueField.tsx @@ -21,7 +21,7 @@ const MemoValueField = ({ onChange, account, transaction, status }: Props) => { invariant(transaction.family === "solana", "Memo: solana family expected"); const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memo => { + (memo: string) => { onChange( bridge.updateTransaction(transaction, { model: { diff --git a/apps/ledger-live-desktop/src/renderer/families/solana/shared/fields/ValidatorsField.tsx b/apps/ledger-live-desktop/src/renderer/families/solana/shared/fields/ValidatorsField.tsx index 5dae28b97d22..f701363eb389 100644 --- a/apps/ledger-live-desktop/src/renderer/families/solana/shared/fields/ValidatorsField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/solana/shared/fields/ValidatorsField.tsx @@ -31,7 +31,10 @@ const ValidatorField = ({ account, onChangeValidator, chosenVoteAccAddr }: Props } }, [validators, chosenVoteAccAddr]); - const onSearch = useCallback(evt => setSearch(evt.target.value), [setSearch]); + const onSearch = useCallback( + (evt: React.ChangeEvent) => setSearch(evt.target.value), + [setSearch], + ); const renderItem = (validator: ValidatorsAppValidator) => { return ( { const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memoValue => { + (memoValue: string) => { onChange(bridge.updateTransaction(transaction, { memo: memoValue })); }, [onChange, transaction, bridge], diff --git a/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/Body.tsx index b7f3a77bd493..462672ff6d6a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/Body.tsx @@ -97,7 +97,7 @@ const Body = ({ t, stepId, device, onClose, openModal, onChangeStepId, params }: }; }); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleRetry = useCallback(() => { setTransactionError(null); onChangeStepId("assets"); diff --git a/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/steps/StepAsset.tsx b/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/steps/StepAsset.tsx index 9fbff161f842..0506ce6ac36a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/steps/StepAsset.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/stellar/AddAssetModal/steps/StepAsset.tsx @@ -11,6 +11,7 @@ import AccountFooter from "~/renderer/modals/Send/AccountFooter"; import Alert from "~/renderer/components/Alert"; import TranslatedError from "~/renderer/components/TranslatedError"; import AssetSelector, { getAssetObject } from "../fields/AssetSelector"; +import { TokenCurrency } from "@ledgerhq/types-cryptoassets"; export default function StepAsset({ account, parentAccount, @@ -24,7 +25,9 @@ export default function StepAsset({ invariant(account && transaction, "account and transaction required"); const bridge = getAccountBridge(account, parentAccount); const onUpdateAsset = useCallback( - ({ id: assetId }) => { + (token?: TokenCurrency | null) => { + if (!token) return; + const { id: assetId } = token; onUpdateTransaction(transaction => bridge.updateTransaction(transaction, getAssetObject(assetId)), ); diff --git a/apps/ledger-live-desktop/src/renderer/families/stellar/FeeField.tsx b/apps/ledger-live-desktop/src/renderer/families/stellar/FeeField.tsx index 4fb66f7a4587..0ad06893c4ec 100644 --- a/apps/ledger-live-desktop/src/renderer/families/stellar/FeeField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/stellar/FeeField.tsx @@ -10,6 +10,7 @@ import Alert from "~/renderer/components/Alert"; import invariant from "invariant"; import { Account } from "@ledgerhq/types-live"; import { Transaction, TransactionStatus } from "@ledgerhq/live-common/families/stellar/types"; +import BigNumber from "bignumber.js"; const FeeField = ({ onChange, @@ -25,7 +26,7 @@ const FeeField = ({ invariant(transaction.family === "stellar", "FeeField: stellar family expected"); const bridge = getAccountBridge(account); const onFeeValueChange = useCallback( - fees => { + (fees: BigNumber) => { onChange( bridge.updateTransaction(transaction, { fees, diff --git a/apps/ledger-live-desktop/src/renderer/families/stellar/MemoTypeField.tsx b/apps/ledger-live-desktop/src/renderer/families/stellar/MemoTypeField.tsx index 03a7ac3d792a..f5579ba0df51 100644 --- a/apps/ledger-live-desktop/src/renderer/families/stellar/MemoTypeField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/stellar/MemoTypeField.tsx @@ -23,6 +23,7 @@ const MemoTypeField = ({ const selectedMemoType = options.find(option => option.value === transaction.memoType) || options[0]; const onMemoTypeChange = useCallback( + // @ts-expect-error weird type here i cannot find the correct option memoType => { onChange( bridge.updateTransaction(transaction, { diff --git a/apps/ledger-live-desktop/src/renderer/families/stellar/MemoValueField.tsx b/apps/ledger-live-desktop/src/renderer/families/stellar/MemoValueField.tsx index 0c4a9bb36e04..2ee008b6fc12 100644 --- a/apps/ledger-live-desktop/src/renderer/families/stellar/MemoValueField.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/stellar/MemoValueField.tsx @@ -17,7 +17,7 @@ const MemoValueField = ({ }) => { const bridge = getAccountBridge(account); const onMemoValueChange = useCallback( - memoValue => { + (memoValue: string) => { onChange(bridge.updateTransaction(transaction, { memoValue })); }, [onChange, transaction, bridge], diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/BakerImage.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/BakerImage.tsx index 7fce6c3e538c..efe692376b79 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/BakerImage.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/BakerImage.tsx @@ -1,9 +1,10 @@ import React from "react"; import styled from "styled-components"; -import { Baker } from "@ledgerhq/live-common/families/tezos/bakers"; +import { Baker } from "@ledgerhq/live-common/families/tezos/types"; import Box from "~/renderer/components/Box"; import CustomValidator from "~/renderer/icons/CustomValidator"; import Image from "~/renderer/components/Image"; + const Circle = styled(Box).attrs((props: { size: number }) => ({ style: { width: props.size, @@ -13,10 +14,12 @@ const Circle = styled(Box).attrs((props: { size: number }) => ({ border-radius: 50%; overflow: hidden; `; + type Props = { size?: number; baker: Baker | undefined | null; }; + const BakerImage = ({ size = 24, baker }: Props) => ( {baker ? ( @@ -26,4 +29,5 @@ const BakerImage = ({ size = 24, baker }: Props) => ( )} ); + export default BakerImage; diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/Body.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/Body.tsx index 4ea5bdf47b29..470acf57a27d 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/Body.tsx @@ -1,11 +1,10 @@ import React, { useEffect, useState, useCallback, useMemo } from "react"; import { bindActionCreators } from "redux"; import { useDispatch, useSelector } from "react-redux"; -import { TFunction } from "i18next"; import { Trans, useTranslation } from "react-i18next"; import invariant from "invariant"; import { Account, AccountLike, Operation, SubAccount } from "@ledgerhq/types-live"; -import { useBakers, useRandomBaker } from "@ledgerhq/live-common/families/tezos/bakers"; +import { useBakers } from "@ledgerhq/live-common/families/tezos/bakers"; import whitelist from "@ledgerhq/live-common/families/tezos/bakers.whitelist-default"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import { getMainAccount, addPendingOperation } from "@ledgerhq/live-common/account/index"; @@ -16,9 +15,7 @@ import logger from "~/renderer/logger"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; import Track from "~/renderer/analytics/Track"; import { getCurrentDevice } from "~/renderer/reducers/devices"; -import { delegatableAccountsSelector } from "~/renderer/actions/general"; import { openModal } from "~/renderer/actions/modals"; - import Stepper from "~/renderer/components/Stepper"; import StepAccount, { StepAccountFooter } from "./steps/StepAccount"; import StepStarter from "./steps/StepStarter"; @@ -27,24 +24,13 @@ import StepSummary, { StepSummaryFooter } from "./steps/StepSummary"; import StepValidator from "./steps/StepValidator"; import StepCustom, { StepCustomFooter } from "./steps/StepCustom"; import StepConfirmation, { StepConfirmationFooter } from "./steps/StepConfirmation"; -import { StepId, St } from "./types"; +import { StepId, Step } from "./types"; import { TezosAccount, TezosOperationMode, Transaction, } from "@ledgerhq/live-common/families/tezos/types"; -const createTitles = (t: TFunction): Record => ({ - account: t("delegation.flow.steps.account.title"), - device: t("delegation.flow.steps.account.title"), // same as account - starter: t("delegation.flow.steps.starter.title"), - summary: t("delegation.flow.steps.summary.title"), - validator: t("delegation.flow.steps.validator.title"), - undelegate: t("delegation.flow.steps.undelegate.title"), - confirmation: t("delegation.flow.steps.confirmation.title"), - custom: t("delegation.flow.steps.custom.title"), -}); - export type Data = { account?: TezosAccount | SubAccount; parentAccount?: TezosAccount | null; @@ -61,7 +47,7 @@ type Props = { params: Data; }; -const createSteps = (params: Data): St[] => [ +const createSteps = (params: Data): Step[] => [ { id: "starter", component: StepStarter, @@ -72,14 +58,14 @@ const createSteps = (params: Data): St[] => [ label: , component: StepAccount, footer: StepAccountFooter, - excludeFromBreadcrumb: Boolean(params && params.account), + excludeFromBreadcrumb: Boolean(params.account), }, { id: "summary", label: , component: StepSummary, footer: StepSummaryFooter, - onBack: params && params.account ? null : ({ transitionTo }) => transitionTo("account"), + onBack: params.account ? null : ({ transitionTo }) => transitionTo("account"), }, { id: "validator", @@ -107,15 +93,15 @@ const createSteps = (params: Data): St[] => [ footer: StepConfirmationFooter, }, ]; -const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { + +const Body = ({ stepId, params, onChangeStepId, onClose }: Props) => { const { t } = useTranslation(); const dispatch = useDispatch(); const device = useSelector(getCurrentDevice); - const accounts = useSelector(delegatableAccountsSelector); const openedFromAccount = !!params.account; - const bakers = useBakers(whitelist); - const randomBaker = useRandomBaker(bakers); - const [steps] = useState(() => createSteps(params)); + const [defaultBaker] = useBakers(whitelist); + const steps = createSteps(params); + const { transaction, setTransaction, @@ -125,12 +111,13 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { status, bridgeError, bridgePending, - } = useBridgeTransaction(() => { - const parentAccount = params && params.parentAccount; - const account = (params && params.account) || accounts[0]; + } = useBridgeTransaction(() => { + const account = params.account; + const parentAccount = params.parentAccount; + return { - account, parentAccount, + account, }; }); @@ -141,21 +128,21 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { // make sure the mode is in sync (an account changes can reset it) const patch: Partial = { - mode: (params && params.mode) || "delegate", + mode: params.mode || "delegate", }; // make sure that in delegate mode, a transaction recipient is set (random pick) - if (patch.mode === "delegate" && !transaction.recipient && stepId !== "custom" && randomBaker) { - patch.recipient = randomBaker.address; + if (patch.mode === "delegate" && !transaction.recipient && stepId !== "custom") { + patch.recipient = defaultBaker.address; } // when changes, we set again - if (patch.mode !== transaction.mode || "recipient" in patch) { + if (patch.mode !== transaction.mode || patch.recipient) { setTransaction( getAccountBridge(account, parentAccount).updateTransaction(transaction, patch), ); } - }, [account, randomBaker, stepId, params, parentAccount, setTransaction, transaction]); + }, [account, defaultBaker, stepId, params, parentAccount, setTransaction, transaction]); // make sure step id is in sync useEffect(() => { @@ -174,17 +161,20 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { }, [account, setAccount], ); + const handleRetry = useCallback(() => { setTransactionError(null); setOptimisticOperation(null); setSigned(false); }, []); + const handleTransactionError = useCallback((error: Error) => { if (!(error instanceof UserRefusedOnDevice)) { logger.critical(error); } setTransactionError(error); }, []); + const handleOperationBroadcasted = useCallback( (optimisticOperation: Operation) => { if (!account) return; @@ -199,22 +189,40 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { }, [account, parentAccount, dispatch], ); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); - const titles = useMemo(() => createTitles(t), [t]); - const title = - transaction && transaction.family === "tezos" && transaction.mode === "undelegate" + + const handleStepChange = useCallback((e: Step) => onChangeStepId(e.id), [onChangeStepId]); + + const titles = useMemo(() => { + const titles: Record = { + account: t("delegation.flow.steps.account.title"), + device: t("delegation.flow.steps.account.title"), // same as account + starter: t("delegation.flow.steps.starter.title"), + summary: t("delegation.flow.steps.summary.title"), + validator: t("delegation.flow.steps.validator.title"), + undelegate: t("delegation.flow.steps.undelegate.title"), + confirmation: t("delegation.flow.steps.confirmation.title"), + custom: t("delegation.flow.steps.custom.title"), + }; + + return titles; + }, [t]); + + const title = useMemo(() => { + return transaction && transaction.family === "tezos" && transaction.mode === "undelegate" ? titles.undelegate : (stepId ? titles[stepId] : undefined) || titles.account; + }, [stepId, titles, transaction]); + const errorSteps = []; if (transactionError) { errorSteps.push(2); } else if (bridgeError) { errorSteps.push(1); } - const isRandomChoice = - !transaction || !randomBaker || transaction.recipient === randomBaker.address; + const error = transactionError || bridgeError; const { account: accountParams, eventType, source = "Account Page" } = params || {}; + const stepperProps = { title, stepId, @@ -236,20 +244,21 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { status, bridgePending, signed, - setSigned, optimisticOperation, + source, + setSigned, openModal: handleOpenModal, onClose, - isRandomChoice, onChangeAccount: handleChangeAccount, onChangeTransaction: setTransaction, onRetry: handleRetry, onStepChange: handleStepChange, onOperationBroadcasted: handleOperationBroadcasted, onTransactionError: handleTransactionError, - source, }; + if (!status) return null; + return ( @@ -257,4 +266,5 @@ const Body = ({ onChangeStepId, onClose, stepId, params }: Props) => { ); }; + export default Body; diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepSummary.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepSummary.tsx index 63b35c84e9b6..c68b55ea6787 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepSummary.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepSummary.tsx @@ -6,7 +6,8 @@ import { getAccountName, getAccountUnit, } from "@ledgerhq/live-common/account/index"; -import { useBaker, useDelegation, Baker } from "@ledgerhq/live-common/families/tezos/bakers"; +import { useBaker, useDelegation } from "@ledgerhq/live-common/families/tezos/bakers"; +import { Baker } from "@ledgerhq/live-common/families/tezos/types"; import { Trans } from "react-i18next"; import TrackPage from "~/renderer/analytics/TrackPage"; import { openURL } from "~/renderer/linking"; @@ -23,7 +24,9 @@ import InfoCircle from "~/renderer/icons/InfoCircle"; import BakerImage from "../../BakerImage"; import DelegationContainer from "../DelegationContainer"; import { StepProps } from "../types"; + const urlDelegationHelp = "https://support.ledger.com/hc/en-us/articles/360010653260"; + const Container = styled(Box)` width: 148px; min-height: 170px; @@ -41,16 +44,12 @@ const Container = styled(Box)` margin-bottom: 10px; } `; + const Placeholder = styled(Box)` height: 14px; `; -const StepSummary = ({ - account, - transaction, - transitionTo, - isRandomChoice, - eventType, -}: StepProps) => { + +const StepSummary = ({ account, transaction, eventType, transitionTo }: StepProps) => { invariant( account && transaction && transaction.family === "tezos", "step summary requires account and transaction settled", @@ -61,6 +60,7 @@ const StepSummary = ({ const unit = getAccountUnit(account); const getBakerName = (baker: Baker | undefined | null, fallback: string) => baker ? baker.name : fallback; + return ( )} - - {isRandomChoice ? ( - - - - ) : null} ) : delegation ? ( @@ -213,7 +207,9 @@ const StepSummary = ({ ); }; + export default StepSummary; + export const StepSummaryFooter = ({ t, account, diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepValidator.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepValidator.tsx index a1b43d20aaef..6490c47421de 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepValidator.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/steps/StepValidator.tsx @@ -3,7 +3,8 @@ import invariant from "invariant"; import styled from "styled-components"; import { Trans } from "react-i18next"; import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; -import { useBakers, Baker } from "@ledgerhq/live-common/families/tezos/bakers"; +import { useBakers } from "@ledgerhq/live-common/families/tezos/bakers"; +import { Baker } from "@ledgerhq/live-common/families/tezos/types"; import bakersWhitelistDefault from "@ledgerhq/live-common/families/tezos/bakers.whitelist-default"; import { openURL } from "~/renderer/linking"; import TrackPage from "~/renderer/analytics/TrackPage"; @@ -14,6 +15,7 @@ import ModalContent from "~/renderer/components/Modal/ModalContent"; import UserPlusIcon from "~/renderer/icons/UserPlus"; import BakerImage from "../../BakerImage"; import { StepProps } from "../types"; + const Row = styled(Box).attrs(() => ({ horizontal: true, }))` @@ -35,6 +37,7 @@ const Row = styled(Box).attrs(() => ({ margin-bottom: 0; } `; + const BakerRow = ({ baker, onClick }: { baker: Baker; onClick: (a: Baker) => void }) => ( onClick(baker)}> @@ -74,6 +77,7 @@ const BakerRow = ({ baker, onClick }: { baker: Baker; onClick: (a: Baker) => voi ); + const StepValidator = ({ account, parentAccount, @@ -85,8 +89,9 @@ const StepValidator = ({ invariant(account, "account is required"); const contentRef = useRef(null); const bakers = useBakers(bakersWhitelistDefault); + const onBakerClick = useCallback( - baker => { + (baker: Baker) => { onChangeTransaction( getAccountBridge(account, parentAccount).updateTransaction(transaction, { recipient: baker.address, @@ -96,9 +101,11 @@ const StepValidator = ({ }, [account, onChangeTransaction, parentAccount, transaction, transitionTo], ); + const openPartner = useCallback(() => { openURL("https://baking-bad.org/"); }, []); + return ( ); }; + export default StepValidator; diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/types.ts b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/types.ts index 0cfb78306ad7..0bfa2137ab2a 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/types.ts +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/DelegateFlowModal/types.ts @@ -2,8 +2,9 @@ import { TFunction } from "i18next"; import { Account, AccountLike, Operation } from "@ledgerhq/types-live"; import { Transaction, TransactionStatus } from "@ledgerhq/live-common/families/tezos/types"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; -import { Step } from "~/renderer/components/Stepper"; +import { Step as StepperProps } from "~/renderer/components/Stepper"; import { OpenModal } from "~/renderer/actions/modals"; + export type StepId = | "starter" | "account" @@ -12,6 +13,7 @@ export type StepId = | "custom" | "device" | "confirmation"; + export type StepProps = { t: TFunction; transitionTo: (a: string) => void; @@ -34,8 +36,8 @@ export type StepProps = { onRetry: (a: void) => void; setSigned: (a: boolean) => void; signed: boolean; - isRandomChoice: boolean; openedWithAccount: boolean; source?: string; }; -export type St = Step; + +export type Step = StepperProps; diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/Row.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/Row.tsx index e9ac44604542..f71a3b0faa9e 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/Row.tsx @@ -14,7 +14,7 @@ import { getAddressExplorer, } from "@ledgerhq/live-common/explorers"; import { SubAccount } from "@ledgerhq/types-live"; -import { Delegation } from "@ledgerhq/live-common/families/tezos/bakers"; +import { Delegation } from "@ledgerhq/live-common/families/tezos/types"; import { openURL } from "~/renderer/linking"; import CounterValue from "~/renderer/components/CounterValue"; import FormattedVal from "~/renderer/components/FormattedVal"; diff --git a/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/index.tsx b/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/index.tsx index df0b4f4a2dcf..141ddabf6224 100644 --- a/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/families/tezos/Delegation/index.tsx @@ -53,7 +53,9 @@ const Delegation = ({ account, parentAccount }: Props) => { }} > - {t("delegation.delegationEarn")} + {t("delegation.delegationEarn", { + name: (account as TezosAccount).currency.name, + })} { + (address: string) => { const url = getAddressExplorer(getDefaultExplorerView(account.currency), address); if (url) openURL(url); }, diff --git a/apps/ledger-live-desktop/src/renderer/hooks/useBraze.ts b/apps/ledger-live-desktop/src/renderer/hooks/useBraze.ts index 75cc88990748..ec5fa26abb29 100644 --- a/apps/ledger-live-desktop/src/renderer/hooks/useBraze.ts +++ b/apps/ledger-live-desktop/src/renderer/hooks/useBraze.ts @@ -28,7 +28,7 @@ export const mapAsPortfolioContentCard = (card: ClassicCard) => image: card.extras?.image, url: card.extras?.url, path: card.extras?.path, - } as PortfolioContentCard); + }) as PortfolioContentCard; export const mapAsNotificationContentCard = (card: ClassicCard) => ({ @@ -41,7 +41,7 @@ export const mapAsNotificationContentCard = (card: ClassicCard) => cta: card.extras?.cta, createdAt: card.created, viewed: card.viewed, - } as NotificationContentCard); + }) as NotificationContentCard; export async function useBraze() { const dispatch = useDispatch(); diff --git a/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts b/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts index 66f84f54ddd3..3be595498059 100644 --- a/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts +++ b/apps/ledger-live-desktop/src/renderer/hooks/useDeeplinking.ts @@ -71,7 +71,7 @@ export function useDeepLinkHandler() { [history, location], ); const handler = useCallback( - (_, deeplink: string) => { + (_: unknown, deeplink: string) => { const { pathname, searchParams, search } = new URL(deeplink); /** * TODO: handle duplicated query params diff --git a/apps/ledger-live-desktop/src/renderer/hooks/useNftLinks.ts b/apps/ledger-live-desktop/src/renderer/hooks/useNftLinks.ts index 0fe4cf0f3d04..8858ef24b1e7 100644 --- a/apps/ledger-live-desktop/src/renderer/hooks/useNftLinks.ts +++ b/apps/ledger-live-desktop/src/renderer/hooks/useNftLinks.ts @@ -1,5 +1,5 @@ import { useMemo } from "react"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { TFunction } from "i18next"; import { useTranslation } from "react-i18next"; import { Account, ProtoNFT, NFTMetadata, NFTMedias } from "@ledgerhq/types-live"; @@ -14,6 +14,8 @@ import { setDrawer } from "../drawers/Provider"; import CustomImage from "~/renderer/screens/customImage"; import NFTViewerDrawer from "~/renderer/drawers/NFTViewerDrawer"; import { ContextMenuItemType } from "../components/ContextMenu/ContextMenuWrapper"; +import { devicesModelListSelector } from "../reducers/settings"; +import { DeviceModelId } from "@ledgerhq/devices"; function safeList(items: (ContextMenuItemType | "" | undefined)[]): ContextMenuItemType[] { return items.filter(Boolean) as ContextMenuItemType[]; @@ -166,21 +168,25 @@ export default ( }, [account, customImageUri, isInsideDrawer, nft.id, t]); const customImageEnabled = useFeature("customImage")?.enabled; + const devicesModelList = useSelector(devicesModelListSelector); const links = useMemo(() => { const metadataLinks = linksPerCurrency[account.currency.id]?.(t, metadata?.links) || []; return [ ...metadataLinks, - ...(customImageEnabled && customImageUri ? [customImage] : []), + ...(devicesModelList?.includes(DeviceModelId.stax) && customImageEnabled && customImageUri + ? [customImage] + : []), hideCollection, ]; }, [ account.currency.id, - hideCollection, + t, metadata?.links, - customImageUri, + devicesModelList, customImageEnabled, + customImageUri, customImage, - t, + hideCollection, ]); return links; }; diff --git a/apps/ledger-live-desktop/src/renderer/icons/SwapCircle.tsx b/apps/ledger-live-desktop/src/renderer/icons/SwapCircle.tsx deleted file mode 100644 index 9b838125f2ef..000000000000 --- a/apps/ledger-live-desktop/src/renderer/icons/SwapCircle.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import React from "react"; -const SwapCircle = ({ size = 15, color = "currentColor" }: { size?: number; color?: string }) => ( - - - - -); -export default SwapCircle; diff --git a/apps/ledger-live-desktop/src/renderer/index.ts b/apps/ledger-live-desktop/src/renderer/index.ts index cbdfcf7f29e9..ac36017d2e4f 100644 --- a/apps/ledger-live-desktop/src/renderer/index.ts +++ b/apps/ledger-live-desktop/src/renderer/index.ts @@ -1,3 +1,4 @@ -import "~/env"; +import "./pre"; +import "~/renderer/env"; import "~/renderer/experimental"; // NB we need to load this first because it loads things from process.env and will setEnv properly at boot import "~/renderer/init"; diff --git a/apps/ledger-live-desktop/src/renderer/init.tsx b/apps/ledger-live-desktop/src/renderer/init.tsx index 083da149c2da..4e0771188408 100644 --- a/apps/ledger-live-desktop/src/renderer/init.tsx +++ b/apps/ledger-live-desktop/src/renderer/init.tsx @@ -9,7 +9,7 @@ import { importPostOnboardingState } from "@ledgerhq/live-common/postOnboarding/ import i18n from "i18next"; import { webFrame, ipcRenderer } from "electron"; import * as remote from "@electron/remote"; -import { render } from "react-dom"; +import { createRoot } from "react-dom/client"; import moment from "moment"; import each from "lodash/each"; import { reload, getKey, loadLSS } from "~/renderer/storage"; @@ -48,10 +48,13 @@ import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { listCachedCurrencyIds } from "./bridge/cache"; import { LogEntry } from "winston"; -const rootNode = document.getElementById("react-root"); +const domNode = document.getElementById("react-root"); const TAB_KEY = 9; async function init() { + // at this step. we know the app error handling will happen here. so we can unset the global onerror + window.onerror = null; + const logVerbose = getEnv("VERBOSE"); // Sets up a debug console printing of logs (from the renderer thread) @@ -246,8 +249,9 @@ async function init() { }; } function r(Comp: JSX.Element) { - if (rootNode) { - render(Comp, rootNode); + if (domNode) { + const rootNode = createRoot(domNode); + rootNode.render(Comp); } } init() diff --git a/apps/ledger-live-desktop/src/renderer/modals/AddAccounts/steps/StepChooseCurrency.tsx b/apps/ledger-live-desktop/src/renderer/modals/AddAccounts/steps/StepChooseCurrency.tsx index fd607e593f52..3cd25c759f25 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/AddAccounts/steps/StepChooseCurrency.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/AddAccounts/steps/StepChooseCurrency.tsx @@ -39,6 +39,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => { const umee = useFeature("currencyUmee"); const desmos = useFeature("currencyDesmos"); const onomy = useFeature("currencyOnomy"); + const seiNetwork = useFeature("currencySeiNetwork"); const quicksilver = useFeature("currencyQuicksilver"); const persistence = useFeature("currencyPersistence"); const avaxCChain = useFeature("currencyAvalancheCChain"); @@ -78,6 +79,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => { umee, desmos, onomy, + sei_network: seiNetwork, quicksilver, persistence, avalanche_c_chain: avaxCChain, @@ -115,6 +117,7 @@ const StepChooseCurrency = ({ currency, setCurrency }: StepProps) => { umee, desmos, onomy, + seiNetwork, quicksilver, persistence, avaxCChain, diff --git a/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Body.tsx index 8c5574d588a4..767f48a0c199 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Body.tsx @@ -29,11 +29,8 @@ const Body = ({ onClose, token }: { onClose?: () => void; token: TokenCurrency } }} > {"This action will hide all "} - {/* $FlowFixMe */} - {{ - tokenName: token.name, - }} + {token.name} {"accounts, you can restore their visibility at any time from "} diff --git a/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Footer.tsx b/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Footer.tsx index f1b72c0a0d88..16c5760e2334 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Footer.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/BlacklistToken/Footer.tsx @@ -9,7 +9,7 @@ import { TokenCurrency } from "@ledgerhq/types-cryptoassets"; const Footer = ({ onClose, token }: { onClose?: () => void; token: TokenCurrency }) => { const dispatch = useDispatch(); const confirmBlacklistToken = useCallback( - tokenId => { + (tokenId: string) => { dispatch(blacklistToken(tokenId)); }, [dispatch], diff --git a/apps/ledger-live-desktop/src/renderer/modals/ExchangeDeviceConfirm/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/ExchangeDeviceConfirm/index.tsx index 2e0816f52a3c..86a40761c13c 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/ExchangeDeviceConfirm/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/ExchangeDeviceConfirm/index.tsx @@ -182,7 +182,7 @@ const Root = ({ data, onClose, skipDevice, flow }: Props) => { [verifyAddress, onResult, account, parentAccount, onClose], ); const onAddressVerified = useCallback( - status => { + (status: boolean) => { if (status) { onResult(account, parentAccount, status); } @@ -297,7 +297,9 @@ const BuyCryptoModal = ({ }; const BuyCrypto = ({ flow }: { flow?: string }) => { const render = useCallback( - ({ data, onClose }) => , + ({ data, onClose }: { data: DataProp; onClose: () => void }) => ( + + ), [flow], ); return ; diff --git a/apps/ledger-live-desktop/src/renderer/modals/ExportOperations/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/ExportOperations/index.tsx index e3432503af71..c13c03561641 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/ExportOperations/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/ExportOperations/index.tsx @@ -188,7 +188,7 @@ const LabelWrapper = styled(Box)` text-align: center; font-size: 13px; font-family: "Inter"; - font-weight: ; + font-weight:; `; const IconWrapperCircle = styled(Box)<{ green?: boolean }>` width: 50px; diff --git a/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Body.tsx index 2ec70c0c2e1f..572412bb44bc 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Body.tsx @@ -36,11 +36,8 @@ const Body = ({ }} > {"This action will hide all NFTs from the "} - {/* $FlowFixMe */} - {{ - collectionName, - }} + {collectionName} {" collection, you can show them again using "} diff --git a/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Footer.tsx b/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Footer.tsx index db3c1628e453..fe699adde96a 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Footer.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/HideNftCollection/Footer.tsx @@ -7,7 +7,7 @@ import { hideNftCollection } from "~/renderer/actions/settings"; const Footer = ({ onClose, collectionId }: { onClose: () => void; collectionId: string }) => { const dispatch = useDispatch(); const confirmHideNftCollection = useCallback( - collectionId => { + (collectionId: string) => { dispatch(hideNftCollection(collectionId)); }, [dispatch], diff --git a/apps/ledger-live-desktop/src/renderer/modals/NoFundsStake/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/NoFundsStake/index.tsx index 0407ee821de2..8aca0ed9e00f 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/NoFundsStake/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/NoFundsStake/index.tsx @@ -3,11 +3,10 @@ import { useDispatch } from "react-redux"; import { useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; import { Icon, Text } from "@ledgerhq/react-ui"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; -import { getAllSupportedCryptoCurrencyTickers } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; + import { Account, AccountLike } from "@ledgerhq/types-live"; import { closeModal, openModal } from "~/renderer/actions/modals"; -import { useProviders } from "~/renderer/screens/exchange/Swap2/Form"; import Modal, { ModalBody } from "~/renderer/components/Modal"; import Box from "~/renderer/components/Box"; import EntryButton from "~/renderer/components/EntryButton/EntryButton"; @@ -15,6 +14,7 @@ import CoinsIcon from "./assets/CoinsIcon"; import { trackPage, track } from "~/renderer/analytics/segment"; import { stakeDefaultTrack } from "~/renderer/screens/stake/constants"; import { CryptoCurrency } from "@ledgerhq/types-cryptoassets"; +import { useFetchCurrencyAll } from "@ledgerhq/live-common/exchange/swap/hooks/index"; const useText = (entryPoint: "noFunds" | "getFunds", currency: CryptoCurrency) => { const { t } = useTranslation(); @@ -43,34 +43,17 @@ const NoFundsStakeModal = ({ account, parentAccount, entryPoint }: NoFundsStakeM const { t } = useTranslation(); const dispatch = useDispatch(); const history = useHistory(); - - const rampCatalog = useRampCatalog(); - const { providers, storedProviders } = useProviders(); - - const onRampAvailableTickers: string[] = useMemo(() => { - if (!rampCatalog.value) { - return []; - } - return getAllSupportedCryptoCurrencyTickers(rampCatalog.value.onRamp); - }, [rampCatalog.value]); - - const swapAvailableIds = useMemo(() => { - return providers || storedProviders - ? (providers || storedProviders)! - .map(({ pairs }) => pairs.map(({ from, to }) => [from, to])) - .flat(2) - : []; - }, [providers, storedProviders]); + const { data: currenciesAll } = useFetchCurrencyAll(); const currency: CryptoCurrency = parentAccount?.currency || (account as Account).currency; - const text = useText(entryPoint === "get-funds" ? "getFunds" : "noFunds", currency); + const { isCurrencyAvailable } = useRampCatalog(); - const availableOnBuy = currency && onRampAvailableTickers.includes(currency.ticker.toUpperCase()); + const availableOnBuy = !!currency && isCurrencyAvailable(currency.id, "onRamp"); const availableOnSwap = useMemo(() => { - return currency && swapAvailableIds.includes(currency.id); - }, [currency, swapAvailableIds]); + return currency && currenciesAll.includes(currency.id); + }, [currency, currenciesAll]); const availableOnReceive = true; @@ -150,6 +133,8 @@ const NoFundsStakeModal = ({ account, parentAccount, entryPoint }: NoFundsStakeM i === 0 ? `${action.substring(0, 1).toUpperCase()}${action.slice(1)}` : action, ); + const text = useText(entryPoint === "get-funds" ? "getFunds" : "noFunds", currency); + return ( void | undefined const dispatch = useDispatch(); const { onResult, onCancel, swapId, rate, ...exchangeParams } = data; const { exchange, provider, transaction: transactionParams } = exchangeParams; + const { amount } = transactionParams; const { fromAccount: account, fromParentAccount: parentAccount, toAccount, } = exchange as ExchangeSwap; - const request = { ...exchangeParams }; + + const magnitudeAwareRate = getMagnitudeAwareRate({ + fromAccount: account, + toAccount, + rate, + }); + const amountExpectedTo = +amount * +magnitudeAwareRate; + + const request = { ...exchangeParams, amountExpectedTo }; const tokenCurrency: TokenCurrency | undefined = account.type === "TokenAccount" ? account.token : undefined; @@ -72,13 +81,10 @@ const Body = ({ data, onClose }: { data: Data; onClose?: () => void | undefined broadcast(signedOperation).then(operation => { // Save swap history if (swapId && rate && toAccount) { - const { result, magnitudeAwareRate } = convertParametersToValidFormat({ + const result = { operation, swapId, - fromAccount: account, - toAccount, - rate, - }); + }; setBroadcastTransaction({ result, provider, @@ -112,6 +118,7 @@ const Body = ({ data, onClose }: { data: Data; onClose?: () => void | undefined onResult, signedOperation, transaction, + magnitudeAwareRate, ]); return ( diff --git a/apps/ledger-live-desktop/src/renderer/modals/ProtectDiscover/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/ProtectDiscover/index.tsx index 5469d2d26f96..110fb95f22b8 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/ProtectDiscover/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/ProtectDiscover/index.tsx @@ -13,7 +13,10 @@ const bodyStyle = { }; const ProtectDiscoverModal = () => { - const renderBody = useCallback(({ onClose }) => , []); + const renderBody = useCallback( + ({ onClose }: { onClose: () => void }) => , + [], + ); return ( diff --git a/apps/ledger-live-desktop/src/renderer/modals/Receive/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/Receive/Body.tsx index a9a938da2897..2d27837ff154 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/Receive/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/Receive/Body.tsx @@ -6,7 +6,7 @@ import { Trans, withTranslation } from "react-i18next"; import { createStructuredSelector } from "reselect"; import { SyncSkipUnderPriority } from "@ledgerhq/live-common/bridge/react/index"; import Track from "~/renderer/analytics/Track"; -import { Account, AccountLike } from "@ledgerhq/types-live"; +import { Account, AccountLike, SubAccount } from "@ledgerhq/types-live"; import { TokenCurrency } from "@ledgerhq/types-cryptoassets"; import { Device } from "@ledgerhq/live-common/hw/actions/types"; import { getAccountCurrency } from "@ledgerhq/live-common/account/helpers"; @@ -132,7 +132,7 @@ const Body = ({ const currency = getAccountCurrency(account); const currencyName = currency ? currency.name : undefined; const handleChangeAccount = useCallback( - (account, parentAccount) => { + (account: Account | SubAccount, parentAccount?: Account | null) => { setAccount(account); setParentAccount(parentAccount); }, @@ -141,7 +141,11 @@ const Body = ({ const handleCloseModal = useCallback(() => { closeModal("MODAL_RECEIVE"); }, [closeModal]); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + + const handleStepChange = useCallback( + (e: Step) => onChangeStepId(e.id), + [onChangeStepId], + ); const handleResetSkip = useCallback(() => { setDisabledSteps([]); }, [setDisabledSteps]); @@ -164,9 +168,9 @@ const Body = ({ useEffect(() => { if (!account) { if (params && params.account) { - handleChangeAccount(params.account, params.parentAccount); + handleChangeAccount(params.account, params?.parentAccount); } else { - handleChangeAccount(accounts[0], null); + handleChangeAccount(accounts[0]); } } }, [accounts, account, params, handleChangeAccount]); diff --git a/apps/ledger-live-desktop/src/renderer/modals/Receive/steps/StepAccount.tsx b/apps/ledger-live-desktop/src/renderer/modals/Receive/steps/StepAccount.tsx index 1abefc6ec0cb..0a670d6833e0 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/Receive/steps/StepAccount.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/Receive/steps/StepAccount.tsx @@ -47,7 +47,7 @@ const TokenParentSelection = ({ mainAccount: Account; }) => { const filterAccountSelect = useCallback( - a => getAccountCurrency(a) === mainAccount.currency, + (a: AccountLike) => getAccountCurrency(a) === mainAccount.currency, [mainAccount], ); return ( diff --git a/apps/ledger-live-desktop/src/renderer/modals/Send/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/Send/Body.tsx index 598c18981dc4..3ba334e11ffb 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/Send/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/Send/Body.tsx @@ -11,7 +11,7 @@ import { addPendingOperation, getMainAccount } from "@ledgerhq/live-common/accou import { getNFT, getNftCapabilities, decodeNftId } from "@ledgerhq/live-common/nft/index"; import { getAccountCurrency } from "@ledgerhq/live-common/account/helpers"; import useBridgeTransaction from "@ledgerhq/live-common/bridge/useBridgeTransaction"; -import { Account, AccountLike, Operation } from "@ledgerhq/types-live"; +import { Account, AccountLike, NFT, NFTStandard, Operation } from "@ledgerhq/types-live"; import { Transaction } from "@ledgerhq/live-common/generated/types"; import logger from "~/renderer/logger"; import Stepper from "~/renderer/components/Stepper"; @@ -227,13 +227,13 @@ const Body = ({ [account, setAccount], ); const handleChangeNFT = useCallback( - nextNft => { + (nextNft: NFT) => { setAccount(mainAccount, undefined); const specific = getLLDCoinFamily(mainAccount.currency.family); if (!specific.nft || !transaction) return; const bridge = getAccountBridge(mainAccount); - const standard = nextNft.standard.toLowerCase(); + const standard = nextNft.standard.toLowerCase() as NFTStandard; const newTransaction = specific.nft.injectNftIntoTransaction( transaction, { @@ -249,7 +249,7 @@ const Body = ({ [mainAccount, setAccount, setTransaction, transaction], ); const handleChangeQuantities = useCallback( - nextQuantity => { + (nextQuantity: string) => { const specific = getLLDCoinFamily(mainAccount.currency.family); if (!specific.nft || !transaction) return; @@ -289,7 +289,10 @@ const Body = ({ }, [account, parentAccount, updateAccountWithUpdater], ); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback( + (e: { id: StepId }) => onChangeStepId(e.id), + [onChangeStepId], + ); const errorSteps = []; if (transactionError) { errorSteps.push(3); diff --git a/apps/ledger-live-desktop/src/renderer/modals/Send/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/Send/index.tsx index 5882f69a9b93..cd78ee1f6b1e 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/Send/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/Send/index.tsx @@ -21,7 +21,7 @@ const MODAL_LOCKED: { const SendModal = ({ stepId: initialStepId, onClose }: Props) => { const [stepId, setStep] = useState(() => initialStepId || "recipient"); const handleReset = useCallback(() => setStep("recipient"), []); - const handleStepChange = useCallback(stepId => setStep(stepId), []); + const handleStepChange = useCallback((stepId: StepId) => setStep(stepId), []); const isModalLocked = MODAL_LOCKED[stepId as StepId]; return ( diff --git a/apps/ledger-live-desktop/src/renderer/modals/SignMessage/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/SignMessage/Body.tsx index 194735a6a5e4..71423ee00cfb 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/SignMessage/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/SignMessage/Body.tsx @@ -39,7 +39,7 @@ const steps: Array = [ const Body = ({ onClose, data }: Props) => { const { t } = useTranslation(); const [stepId, setStepId] = useState("summary"); - const handleStepChange = useCallback(e => setStepId(e.id), [setStepId]); + const handleStepChange = useCallback((e: { id: string }) => setStepId(e.id), [setStepId]); const stepperOnClose = useCallback(() => { if (onClose) { onClose(); diff --git a/apps/ledger-live-desktop/src/renderer/modals/SignTransaction/Body.tsx b/apps/ledger-live-desktop/src/renderer/modals/SignTransaction/Body.tsx index 5a10a4ff80b5..2caa3859395a 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/SignTransaction/Body.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/SignTransaction/Body.tsx @@ -20,6 +20,7 @@ import { getAccountBridge } from "@ledgerhq/live-common/bridge/index"; import logger from "~/renderer/logger"; import Text from "~/renderer/components/Text"; import { TransactionStatus } from "@ledgerhq/live-common/generated/types"; +import { ModalData } from "../types"; export type Params = { canEditFees: boolean; @@ -142,7 +143,11 @@ export default function Body({ onChangeStepId, onClose, setError, stepId, params }; }); const [transactionError, setTransactionError] = useState(null); - const handleOpenModal = useCallback((name, data) => dispatch(openModal(name, data)), [dispatch]); + const handleOpenModal = useCallback( + (name: Name, data: ModalData[Name]) => + dispatch(openModal(name, data)), + [dispatch], + ); const handleCloseModal = useCallback(() => { dispatch(closeModal("MODAL_SIGN_TRANSACTION")); }, [dispatch]); @@ -168,7 +173,7 @@ export default function Body({ onChangeStepId, onClose, setError, stepId, params }, [setError], ); - const handleStepChange = useCallback(e => onChangeStepId(e.id), [onChangeStepId]); + const handleStepChange = useCallback((e: St) => onChangeStepId(e.id), [onChangeStepId]); const handleTransactionSigned = useCallback( (signedTransaction: SignedOperation) => { params.onResult(signedTransaction); diff --git a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Cancel.tsx b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Cancel.tsx new file mode 100644 index 000000000000..3216678a19c2 --- /dev/null +++ b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Cancel.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import { Button, Divider, Flex, IconsLegacy, Link } from "@ledgerhq/react-ui"; +import { useTranslation } from "react-i18next"; +import { ErrorBody } from "~/renderer/components/DeviceAction/rendering"; + +type Props = { + onContinue: () => void; + onCancel: () => void; +}; + +const Cancel = ({ onContinue, onCancel }: Props) => { + const { t } = useTranslation(); + + return ( + + + } + title={t("manager.firmware.updateInProgress")} + description={t("manager.firmware.cancelUpdateWarning")} + /> + + + + {t("manager.firmware.cancelUpdate")} + + + + + ); +}; + +export default Cancel; diff --git a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Disclaimer.tsx b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Disclaimer.tsx index 8c2cd4102067..38579f273266 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Disclaimer.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/Disclaimer.tsx @@ -27,7 +27,8 @@ const Disclaimer = ({ firmware, onContinue, t }: Props) => ( {firmware && firmware.osu ? (
- {firmware.osu.notes} + {/* */} + {firmware.osu.notes as string}
) : null} @@ -44,7 +45,7 @@ const Disclaimer = ({ firmware, onContinue, t }: Props) => ( >
diff --git a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/index.tsx b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/index.tsx index e4bc9d3e8326..1ec3403fc956 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/index.tsx @@ -15,6 +15,8 @@ import { isDeviceLocalizationSupported } from "@ledgerhq/live-common/manager/loc import StepConfirmation, { StepConfirmFooter } from "./steps/03-step-confirmation"; import { Divider, Flex, FlowStepper, Text } from "@ledgerhq/react-ui"; import Disclaimer from "./Disclaimer"; +import Cancel from "./Cancel"; +import SideDrawerHeader from "~/renderer/components/SideDrawerHeader"; type MaybeError = Error | undefined | null; @@ -58,6 +60,7 @@ export type Props = { withResetStep: boolean; withAppsToReinstall: boolean; onDrawerClose: (reinstall?: boolean) => void; + onRequestClose: () => void; firmware?: FirmwareUpdateContext; stepId: StepId; error?: Error | null | undefined; @@ -83,6 +86,7 @@ const UpdateModal = ({ withAppsToReinstall, error, onDrawerClose, + onRequestClose, setFirmwareUpdateCompleted, firmware, ...props @@ -99,6 +103,11 @@ const UpdateModal = ({ const [CLSBackup, setCLSBackup] = useState(); const [updatedDeviceInfo, setUpdatedDeviceInfo] = useState(undefined); const withFinal = useMemo(() => hasFinalFirmware(firmware?.final), [firmware]); + const [cancel, setCancel] = useState(false); + + const onRequestCancel = useCallback(() => { + showDisclaimer || stateStepId === "finish" ? onRequestClose() : setCancel(state => !state); + }, [showDisclaimer, stateStepId, onRequestClose]); const createSteps = useCallback( ({ withResetStep }: { withResetStep: boolean }) => { @@ -232,10 +241,13 @@ const UpdateModal = ({ flex={1} data-test-id="firmware-update-container" > + {t("manager.modal.title", { productName: deviceModel.productName })} - {showDisclaimer ? ( + {cancel ? ( + + ) : showDisclaimer ? ( setShowDisclaimer(false)} t={t} firmware={firmware} /> ) : ( - {t("manager.modal.confirmIdentifierText", { productName: deviceModel.productName })} + {t("manager.modal.confirmIdentifierText")}
); diff --git a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/steps/03-step-confirmation.tsx b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/steps/03-step-confirmation.tsx index db23112300d7..9b8bddf611b0 100644 --- a/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/steps/03-step-confirmation.tsx +++ b/apps/ledger-live-desktop/src/renderer/modals/UpdateFirmwareModal/steps/03-step-confirmation.tsx @@ -6,8 +6,8 @@ import { UserRefusedFirmwareUpdate } from "@ledgerhq/errors"; import { useHistory } from "react-router-dom"; import TrackPage from "~/renderer/analytics/TrackPage"; import Track from "~/renderer/analytics/Track"; +import { getDeviceModel } from "@ledgerhq/devices"; import Box from "~/renderer/components/Box"; -import Text from "~/renderer/components/Text"; import ErrorDisplay from "~/renderer/components/ErrorDisplay"; import { StepProps } from "../"; import { context } from "~/renderer/drawers/Provider"; @@ -27,11 +27,8 @@ const Title = styled(Box).attrs(() => ({ font-weight: 500; `; -const StepConfirmation = ({ - error, - appsToBeReinstalled, - finalStepSuccessDescription, -}: StepProps) => { +const StepConfirmation = ({ error, deviceModelId }: StepProps) => { + const device = getDeviceModel(deviceModelId); const { t } = useTranslation(); useEffect(() => () => log("firmware-record-end"), []); @@ -56,16 +53,9 @@ const StepConfirmation = ({ size={64} iconSize={24} /> - {t("manager.modal.successTitle")} - - - {finalStepSuccessDescription - ? finalStepSuccessDescription - : appsToBeReinstalled - ? t("manager.modal.successTextApps") - : t("manager.modal.successTextNoApps")} - - + + {t("manager.modal.successTitle", { deviceName: device ? device.productName : "" })} + ); diff --git a/apps/ledger-live-desktop/src/renderer/pre.ts b/apps/ledger-live-desktop/src/renderer/pre.ts new file mode 100644 index 000000000000..44e02232ea96 --- /dev/null +++ b/apps/ledger-live-desktop/src/renderer/pre.ts @@ -0,0 +1,10 @@ +// catch all errors during the loading of the app. it will be unset in index.ts at the same time we finish loading it. +window.onerror = e => { + const pre = document.createElement("pre"); + pre.innerHTML = `Ledger Live crashed. Please contact Ledger support. + ${String(e)}`; + document.body.style.padding = "50px"; + document.body.innerHTML = ""; + document.body.style.backgroundColor = "#fff"; + document.body.appendChild(pre); +}; diff --git a/apps/ledger-live-desktop/src/renderer/reducers/settings.ts b/apps/ledger-live-desktop/src/renderer/reducers/settings.ts index 34755e5289a5..d8cc74d8e858 100644 --- a/apps/ledger-live-desktop/src/renderer/reducers/settings.ts +++ b/apps/ledger-live-desktop/src/renderer/reducers/settings.ts @@ -460,12 +460,12 @@ const defaultsForCurrency: (a: Currency) => CurrencySettings = crypto => { }; }; -export type SupportedCoutervaluesData = { +export type SupportedCountervaluesData = { value: string; label: string; currency: Currency; }; -export const supportedCountervalues: SupportedCoutervaluesData[] = [ +export const supportedCountervalues: SupportedCountervaluesData[] = [ ...listSupportedFiats(), ...possibleIntermediaries, ] diff --git a/apps/ledger-live-desktop/src/renderer/screens/USBTroubleshooting/solutions/RepairFunnel.tsx b/apps/ledger-live-desktop/src/renderer/screens/USBTroubleshooting/solutions/RepairFunnel.tsx index d7ae8bddb95c..e636031e861f 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/USBTroubleshooting/solutions/RepairFunnel.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/USBTroubleshooting/solutions/RepairFunnel.tsx @@ -24,7 +24,7 @@ const RepairFunnelSolution = ({ sendEvent("PREVIOUS"); }, [sendEvent]); const onSelectDevice = useCallback( - deviceModel => { + (deviceModel: string) => { if (deviceModel === "nanoS") { // NB click forwarded into the repair button. repairRef.current?.click(); @@ -37,7 +37,7 @@ const RepairFunnelSolution = ({ [repairRef, sendEvent], ); const onRepairDeviceClose = useCallback( - ({ needHelp }) => { + ({ needHelp }: { needHelp?: boolean }) => { if (needHelp) { sendEvent("DONE", { deviceModel: "nanoS", diff --git a/apps/ledger-live-desktop/src/renderer/screens/account/AccountHeaderActions.tsx b/apps/ledger-live-desktop/src/renderer/screens/account/AccountHeaderActions.tsx index 76deed283d4f..24ce74d64fbe 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/account/AccountHeaderActions.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/account/AccountHeaderActions.tsx @@ -4,8 +4,8 @@ import { getMainAccount, isAccountEmpty, } from "@ledgerhq/live-common/account/index"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; -import { getAllSupportedCryptoCurrencyIds } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; + import { Account, AccountLike } from "@ledgerhq/types-live"; import React, { useCallback, useMemo } from "react"; import { TFunction } from "i18next"; @@ -22,7 +22,6 @@ import Tooltip from "~/renderer/components/Tooltip"; import useTheme from "~/renderer/hooks/useTheme"; import IconAccountSettings from "~/renderer/icons/AccountSettings"; import IconWalletConnect from "~/renderer/icons/WalletConnect"; -import { useProviders } from "~/renderer/screens/exchange/Swap2/Form"; import { rgba } from "~/renderer/styles/helpers"; import { track } from "~/renderer/analytics/segment"; import { @@ -37,6 +36,8 @@ import { useGetSwapTrackingProperties } from "~/renderer/screens/exchange/Swap2/ import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; import { getLLDCoinFamily } from "~/renderer/families"; import { ManageAction } from "~/renderer/families/types"; +import { getAvailableProviders } from "@ledgerhq/live-common/exchange/swap/index"; +import { useFetchCurrencyAll } from "@ledgerhq/live-common/exchange/swap/hooks/index"; type RenderActionParams = { label: React.ReactNode; @@ -151,6 +152,7 @@ const AccountHeaderSettingsButtonComponent = ({ account, parentAccount, openModa const pageName = "Page Account"; const AccountHeaderActions = ({ account, parentAccount, openModal }: Props) => { + const { data: currenciesAll } = useFetchCurrencyAll(); const mainAccount = getMainAccount(account, parentAccount); const contrastText = useTheme().colors.palette.text.shade60; const swapDefaultTrack = useGetSwapTrackingProperties(); @@ -167,29 +169,14 @@ const AccountHeaderActions = ({ account, parentAccount, openModal }: Props) => { const ReceiveAction = specific?.accountActions?.ReceiveAction || ReceiveActionDefault; const currency = getAccountCurrency(account); - const rampCatalog = useRampCatalog(); + const { isCurrencyAvailable } = useRampCatalog(); - // eslint-disable-next-line no-unused-vars - const [availableOnBuy, availableOnSell] = useMemo(() => { - if (!rampCatalog.value) { - return [false, false]; - } - const allBuyableCryptoCurrencyIds = getAllSupportedCryptoCurrencyIds(rampCatalog.value.onRamp); - const allSellableCryptoCurrencyIds = getAllSupportedCryptoCurrencyIds( - rampCatalog.value.offRamp, - ); - return [ - allBuyableCryptoCurrencyIds.includes(currency.id), - allSellableCryptoCurrencyIds.includes(currency.id), - ]; - }, [rampCatalog.value, currency.id]); - const { providers, storedProviders, providersError } = useProviders(); + const availableOnBuy = !!currency && isCurrencyAvailable(currency.id, "onRamp"); + const availableOnSell = !!currency && isCurrencyAvailable(currency.id, "offRamp"); // don't show buttons until we know whether or not we can show swap button, otherwise possible click jacking - const showButtons = !!(providers || storedProviders || providersError); - const availableOnSwap = providers?.concat(storedProviders ?? []).some(({ pairs }) => { - return pairs && pairs.find(({ from, to }) => [from, to].includes(currency.id)); - }); + const showButtons = !!getAvailableProviders(); + const availableOnSwap = currenciesAll.includes(currency.id); const history = useHistory(); const buttonSharedTrackingFields = useMemo( diff --git a/apps/ledger-live-desktop/src/renderer/screens/account/EmptyStateAccount.tsx b/apps/ledger-live-desktop/src/renderer/screens/account/EmptyStateAccount.tsx index 67a9db72a8ce..e2fe3eb08591 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/account/EmptyStateAccount.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/account/EmptyStateAccount.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useCallback } from "react"; +import React, { useCallback } from "react"; import { connect } from "react-redux"; import { compose } from "redux"; import { withTranslation, Trans } from "react-i18next"; @@ -15,12 +15,11 @@ import lightEmptyStateAccount from "~/renderer/images/light-empty-state-account. import darkEmptyStateAccount from "~/renderer/images/dark-empty-state-account.svg"; import Text from "~/renderer/components/Text"; import Button from "~/renderer/components/Button"; -import { getAllSupportedCryptoCurrencyIds } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; import styled from "styled-components"; import { useHistory, withRouter } from "react-router-dom"; import { getAccountCurrency } from "@ledgerhq/live-common/account/helpers"; import { setTrackingSource } from "~/renderer/analytics/TrackPage"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; const mapDispatchToProps = { openModal, }; @@ -36,18 +35,11 @@ type Props = OwnProps & { function EmptyStateAccount({ t, account, parentAccount, openModal }: Props) { const mainAccount = getMainAccount(account, parentAccount); const currency = getAccountCurrency(account); - const rampCatalog = useRampCatalog(); + const { isCurrencyAvailable } = useRampCatalog(); const history = useHistory(); - // eslint-disable-next-line no-unused-vars - const availableOnBuy = useMemo(() => { - if (!rampCatalog.value) { - return false; - } - const allBuyableCryptoCurrencyIds = getAllSupportedCryptoCurrencyIds(rampCatalog.value.onRamp); + const availableOnBuy = !!currency && isCurrencyAvailable(currency.id, "onRamp"); - return allBuyableCryptoCurrencyIds.includes(currency.id); - }, [rampCatalog.value, currency.id]); const hasTokens = mainAccount.subAccounts && mainAccount.subAccounts.length && diff --git a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Order.tsx b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Order.tsx index b7ef1ba2d837..084d8cf6df94 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Order.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Order.tsx @@ -20,7 +20,7 @@ export default function Order() { const dispatch = useDispatch(); const { t } = useTranslation(); const onChange = useCallback( - o => { + (o: { key: string; label: string }) => { if (!o) return; dispatch( saveSettings({ @@ -31,7 +31,16 @@ export default function Order() { }, [refreshAccountsOrdering, dispatch], ); - const renderItem = useCallback(props => , []); + const renderItem = useCallback( + (props: { + isActive: boolean; + item: { + key: string; + label: string; + }; + }) => , + [], + ); const items = useMemo( () => ["balance|desc", "balance|asc", "name|asc", "name|desc"].map(key => ({ diff --git a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Range.tsx b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Range.tsx index cfa9b2ecc94a..200ae1ed56f9 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Range.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountList/Range.tsx @@ -35,7 +35,7 @@ const RangeItem = React.memo(function RangeItem({ }); function Range() { const { t } = useTranslation(); - const renderItem = useCallback(props => , []); + const renderItem = useCallback((props: RangeItemProps) => , []); const [range, onRangeChange, rangeItems] = useTimeRange(); return ( // DropDownSelector is not typed well diff --git a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountSyncStatusIndicator.tsx b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountSyncStatusIndicator.tsx index d9e9148c8f37..66431503cb29 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountSyncStatusIndicator.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/accounts/AccountSyncStatusIndicator.tsx @@ -115,7 +115,7 @@ const AccountSyncStatusIndicator = ({ accountId, account, isUpToDateAccount }: P const currency = getAccountCurrency(account); const showSatStackIcon = !!satStackAlreadyConfigured && currency.id === "bitcoin"; const onClick = useCallback( - e => { + (e: React.SyntheticEvent) => { e.stopPropagation(); sync({ type: "SYNC_ONE_ACCOUNT", diff --git a/apps/ledger-live-desktop/src/renderer/screens/asset/AccountDistribution/Row.tsx b/apps/ledger-live-desktop/src/renderer/screens/asset/AccountDistribution/Row.tsx index 81ae5b4f0ac0..bf9dca59bb30 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/asset/AccountDistribution/Row.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/asset/AccountDistribution/Row.tsx @@ -4,7 +4,7 @@ import { BigNumber } from "bignumber.js"; import { useSelector } from "react-redux"; import styled from "styled-components"; import { getAccountName } from "@ledgerhq/live-common/account/index"; -import { AccountLike } from "@ledgerhq/types-live"; +import { Account, AccountLike, SubAccount } from "@ledgerhq/types-live"; import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; import { useCurrencyColor } from "~/renderer/getCurrencyColor"; import CounterValue from "~/renderer/components/CounterValue"; @@ -39,7 +39,7 @@ export default function Row({ const theme = useTheme(); const history = useHistory(); const onAccountClick = useCallback( - account => { + (account: Account | SubAccount) => { setTrackingSource("account allocation"); history.push({ pathname: diff --git a/apps/ledger-live-desktop/src/renderer/screens/asset/AssetBalanceSummaryHeader.tsx b/apps/ledger-live-desktop/src/renderer/screens/asset/AssetBalanceSummaryHeader.tsx index 5c51e9676090..28beccd08879 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/asset/AssetBalanceSummaryHeader.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/asset/AssetBalanceSummaryHeader.tsx @@ -16,13 +16,12 @@ import Button from "~/renderer/components/ButtonV3"; import { setTrackingSource } from "~/renderer/analytics/TrackPage"; import { useHistory } from "react-router-dom"; import { useTranslation } from "react-i18next"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; -import { getAllSupportedCryptoCurrencyIds } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; -import { useProviders } from "../exchange/Swap2/Form"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import useStakeFlow from "~/renderer/screens/stake"; import { stakeDefaultTrack } from "~/renderer/screens/stake/constants"; import { BalanceHistoryWithCountervalue, ValueChange } from "@ledgerhq/types-live"; +import { useFetchCurrencyAll } from "@ledgerhq/live-common/exchange/swap/hooks/index"; type Props = { isAvailable: boolean; cryptoChange: ValueChange; @@ -43,6 +42,7 @@ export default function AssetBalanceSummaryHeader({ currency, unit, }: Props) { + const { data: currenciesAll } = useFetchCurrencyAll(); const swapDefaultTrack = useGetSwapTrackingProperties(); const dispatch = useDispatch(); const { t } = useTranslation(); @@ -71,23 +71,17 @@ export default function AssetBalanceSummaryHeader({ }, [countervalueFirst, data]); const primaryKey = data[0].unit.code; const secondaryKey = data[1].unit.code; - const rampCatalog = useRampCatalog(); - const availableOnBuy = useMemo(() => { - if (!rampCatalog.value) { - return false; - } - const allBuyableCryptoCurrencyIds = getAllSupportedCryptoCurrencyIds(rampCatalog.value.onRamp); - return allBuyableCryptoCurrencyIds.includes(currency.id); - }, [rampCatalog.value, currency.id]); - const { providers, storedProviders } = useProviders(); + const { isCurrencyAvailable } = useRampCatalog(); + + const availableOnBuy = !!currency && isCurrencyAvailable(currency.id, "onRamp"); + const startStakeFlow = useStakeFlow(); const stakeProgramsFeatureFlag = useFeature("stakePrograms"); const listFlag = stakeProgramsFeatureFlag?.params?.list ?? []; const stakeProgramsEnabled = stakeProgramsFeatureFlag?.enabled ?? false; const availableOnStake = stakeProgramsEnabled && currency && listFlag.includes(currency?.id); - const availableOnSwap = providers?.concat(storedProviders ?? []).some(({ pairs }) => { - return pairs && pairs.find(({ from, to }) => [from, to].includes(currency.id)); - }); + + const availableOnSwap = currenciesAll.includes(currency.id); const onBuy = useCallback(() => { setTrackingSource("asset header actions"); diff --git a/apps/ledger-live-desktop/src/renderer/screens/asset/BalanceSummary.tsx b/apps/ledger-live-desktop/src/renderer/screens/asset/BalanceSummary.tsx index 429bae01ee1d..75ecd8c8a3e9 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/asset/BalanceSummary.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/asset/BalanceSummary.tsx @@ -40,7 +40,7 @@ export default function BalanceSummary({ const displayCountervalue = countervalueFirst && countervalueAvailable; const chartMagnitude = displayCountervalue ? counterValue.units[0].magnitude : unit.magnitude; const renderTooltip = useCallback( - d => { + (d: Data[number]) => { const data = [ { val: d.value, diff --git a/apps/ledger-live-desktop/src/renderer/screens/customImage/Step1ChooseImage.tsx b/apps/ledger-live-desktop/src/renderer/screens/customImage/Step1ChooseImage.tsx index 27ad942083b7..091b6feca040 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/customImage/Step1ChooseImage.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/customImage/Step1ChooseImage.tsx @@ -83,10 +83,13 @@ const StepChooseImage: React.FC = props => { * virtual delay to ensure showing loading state at least 400ms so * it doesn't look glitchy if it's too fast */ - setTimeout(() => { - if (!isMounted()) return; - setSelectedNftBase64({ imageBase64DataUri: res as string }); - }, Math.max(0, 400 - (Date.now() - t1))); + setTimeout( + () => { + if (!isMounted()) return; + setSelectedNftBase64({ imageBase64DataUri: res as string }); + }, + Math.max(0, 400 - (Date.now() - t1)), + ); }) .catch(() => { onError(new ImageDownloadError()); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx index d3f3f8982c3e..e7a863bf6282 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/ExchangeDrawer/index.tsx @@ -45,7 +45,7 @@ type Props = { export default function ExchangeDrawer({ swapTransaction, exchangeRate, onCompleteSwap }: Props) { const dispatch = useDispatch(); - const [error, setError] = useState(null); + const [error, setError] = useState(null); const [result, setResult] = useState<{ operation: Operation; swapId: string; @@ -71,13 +71,13 @@ export default function ExchangeDrawer({ swapTransaction, exchangeRate, onComple ) as Exchange; const onError = useCallback( - errorResult => { + (errorResult: { error: Error; swapId?: string }) => { const { error, swapId } = errorResult; // Consider the swap as cancelled (on provider perspective) in case of error postSwapCancelled({ provider: exchangeRate.provider, - swapId, + swapId: swapId ?? "", }); track("error_message", { message: "drawer_error", diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx index 01d9c64dd35b..4158d94a015c 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FeesDrawer/index.tsx @@ -10,7 +10,7 @@ import { import { DrawerTitle } from "../DrawerTitle"; import TrackPage from "~/renderer/analytics/TrackPage"; import { useGetSwapTrackingProperties } from "../../utils/index"; -import { Account } from "@ledgerhq/types-live"; +import { Account, FeeStrategy } from "@ledgerhq/types-live"; type Props = { setTransaction: SwapTransactionType["setTransaction"]; @@ -36,7 +36,7 @@ export default function FeesDrawer({ const transaction = useSelector(transactionSelector); const mapStrategies = useCallback( - strategy => + (strategy: FeeStrategy) => strategy.label === "slow" && disableSlowStrategy ? { ...strategy, diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormLoading/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormLoading/index.tsx deleted file mode 100644 index bd1a84947dd8..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormLoading/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; -import Box from "~/renderer/components/Box"; -import BigSpinner from "~/renderer/components/BigSpinner"; - -const FormLoading = () => ( - - - -); - -export default FormLoading; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormNotAvailable/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormNotAvailable/index.tsx deleted file mode 100644 index e1a89b008550..000000000000 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormNotAvailable/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React from "react"; -import { useTranslation, Trans } from "react-i18next"; -import styled from "styled-components"; -import Text from "~/renderer/components/Text"; -import Box from "~/renderer/components/Box"; -import SwapCircle from "~/renderer/icons/SwapCircle"; -import { useGetSwapTrackingProperties } from "../../utils/index"; -import TrackPage from "~/renderer/analytics/TrackPage"; -const Body = styled(Box).attrs({ - alignItems: "center", - color: "palette.text.shade50", -})` - max-width: 25.5rem; - row-gap: 1.5rem; -`; -const TextSection = styled(Box)` - row-gap: 0.8125rem; -`; -const IconContainer = styled.div` - color: ${p => p.theme.colors.palette.primary.main}; -`; - -const FormNotAvailable = () => { - const { t } = useTranslation(); - const swapDefaultTrack = useGetSwapTrackingProperties(); - - return ( - - - - - - - - - {t("swap2.form.notAvailable.title")} - - - , - }} - /> - - - - - ); -}; - -export default FormNotAvailable; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx index f07565ad6bbf..2b849d47479d 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/FromRow.tsx @@ -1,5 +1,4 @@ import React, { useEffect } from "react"; -import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; import styled from "styled-components"; import { @@ -8,13 +7,11 @@ import { getAccountName, } from "@ledgerhq/live-common/account/index"; import Box from "~/renderer/components/Box"; -import { fromSelector } from "~/renderer/actions/swap"; import InputCurrency from "~/renderer/components/InputCurrency"; import { ErrorContainer } from "~/renderer/components/Input"; import { SelectAccount } from "~/renderer/components/SelectAccount"; import Switch from "~/renderer/components/Switch"; import Text from "~/renderer/components/Text"; -import { shallowAccountsSelector } from "~/renderer/reducers/accounts"; import { amountInputContainerProps, renderAccountValue, selectRowStylesMap } from "./utils"; import { FormLabel } from "./FormLabel"; import { @@ -30,6 +27,9 @@ import { AccountLike } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { TranslatedError } from "~/renderer/components/TranslatedError/TranslatedError"; import { WarningSolidMedium } from "@ledgerhq/react-ui/assets/icons"; +import { useSwapableAccounts } from "@ledgerhq/live-common/exchange/swap/hooks/index"; +import { useSelector } from "react-redux"; +import { flattenAccountsSelector } from "~/renderer/reducers/accounts"; const SwapStatusContainer = styled.div<{ isError: boolean }>( ({ theme: { space, colors }, isError }) => ` @@ -123,7 +123,8 @@ function FromRow({ updateSelectedRate, }: Props) { const swapDefaultTrack = useGetSwapTrackingProperties(); - const accounts = useSelector(fromSelector)(useSelector(shallowAccountsSelector)); + const flattenedAccounts = useSelector(flattenAccountsSelector); + const accounts = useSwapableAccounts({ accounts: flattenedAccounts }); const unit = fromAccount && getAccountUnit(fromAccount); const { t } = useTranslation(); usePickDefaultAccount(accounts, fromAccount, setFromAccount); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx index c9849303f76e..53903d532213 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSelectors/ToRow.tsx @@ -5,13 +5,11 @@ import InputCurrency from "~/renderer/components/InputCurrency"; import SelectCurrency from "~/renderer/components/SelectCurrency"; import { amountInputContainerProps, renderCurrencyValue, selectRowStylesMap } from "./utils"; import { FormLabel } from "./FormLabel"; -import { toSelector } from "~/renderer/actions/swap"; -import { useSelector } from "react-redux"; import { + useFetchCurrencyTo, usePickDefaultCurrency, useSelectableCurrencies, } from "@ledgerhq/live-common/exchange/swap/hooks/index"; -import { getAccountCurrency } from "@ledgerhq/live-common/account/index"; import { SwapSelectorStateType, SwapTransactionType, @@ -60,11 +58,12 @@ function ToRow({ loadingRates, updateSelectedRate, }: Props) { - const fromCurrencyId = fromAccount ? getAccountCurrency(fromAccount).id : undefined; + const { data: currenciesTo, isLoading: currenciesToIsLoading } = useFetchCurrencyTo({ + fromCurrencyAccount: fromAccount, + }); const swapDefaultTrack = useGetSwapTrackingProperties(); - const allCurrencies = useSelector(toSelector)(fromCurrencyId); const currencies = useSelectableCurrencies({ - allCurrencies, + allCurrencies: currenciesTo ?? [], }); const unit = toCurrency?.units[0]; usePickDefaultCurrency(currencies, toCurrency, setToCurrency); @@ -99,7 +98,7 @@ function ToRow({ onChange={setCurrencyAndTrack} value={toCurrency} stylesMap={selectRowStylesMap} - isDisabled={!fromAccount} + isDisabled={!fromAccount || currenciesToIsLoading} renderValueOverride={renderCurrencyValue} onMenuOpen={trackEditCurrency} /> diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx index c8ead7706295..5ebc847c1eda 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/FormSummary/index.tsx @@ -17,7 +17,8 @@ const Form = styled.section.attrs<{ ready?: boolean }>(({ ready }) => ({ display: grid; row-gap: 1.25rem; color: white; - transition: max-height 800ms cubic-bezier(0.47, 0, 0.75, 0.72), + transition: + max-height 800ms cubic-bezier(0.47, 0, 0.75, 0.72), opacity 400ms 400ms cubic-bezier(0.47, 0, 0.75, 0.72); transform-origin: top; height: auto; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Filter.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Filter.tsx index 8ff377f71d86..f8bd031cb434 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Filter.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/Filter.tsx @@ -38,7 +38,7 @@ export const Btn = styled(Button).attrs(p => { export default function Filter({ onClick }: Props) { const [filter, setFilter] = useState([]); const updateFilter = useCallback( - type => { + (type: keyof typeof FILTER) => { let newFilter: string[] = []; if (filter.includes(type)) { newFilter = filter.filter(e => e !== type); diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx index bc3d07bc0807..5a063d23696e 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/Rates/index.tsx @@ -12,6 +12,7 @@ import Filter from "./Filter"; import { SwapSelectorStateType, RatesReducerState, + ExchangeRate, } from "@ledgerhq/live-common/exchange/swap/types"; import { rateSelector, updateRateAction } from "~/renderer/actions/swap"; import TrackPage from "~/renderer/analytics/TrackPage"; @@ -68,8 +69,8 @@ export default function ProviderRate({ ? rates.map(({ toAmount }) => formatCurrencyUnit(getFeesUnit(toCurrency), toAmount)) : []; const updateRate = useCallback( - rate => { - const value = rate ?? rate.provider; + (rate: ExchangeRate) => { + const value = rate.rate ?? rate.provider; track("partner_clicked", { page: "Page Swap Form", ...swapDefaultTrack, diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx index 2ccb2bd343f3..bf2fb9cba4df 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/Form/index.tsx @@ -1,27 +1,21 @@ import { - useSwapProviders, useSwapTransaction, usePageState, + useIsSwapLiveApp, + SetExchangeRateCallback, } from "@ledgerhq/live-common/exchange/swap/hooks/index"; import { getCustomFeesPerFamily, convertToNonAtomicUnit, } from "@ledgerhq/live-common/exchange/swap/webApp/index"; -import { getProviderName, getCustomDappUrl } from "@ledgerhq/live-common/exchange/swap/utils/index"; +import { getProviderName } from "@ledgerhq/live-common/exchange/swap/utils/index"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useDispatch, useSelector } from "react-redux"; import { useHistory, useLocation } from "react-router-dom"; import styled from "styled-components"; import { getParentAccount, isTokenAccount } from "@ledgerhq/live-common/account/index"; -import { - providersSelector, - rateSelector, - resetSwapAction, - updateProvidersAction, - updateRateAction, - updateTransactionAction, -} from "~/renderer/actions/swap"; +import { rateSelector, updateRateAction, updateTransactionAction } from "~/renderer/actions/swap"; import { track } from "~/renderer/analytics/segment"; import TrackPage from "~/renderer/analytics/TrackPage"; import Box from "~/renderer/components/Box"; @@ -30,8 +24,6 @@ import { context } from "~/renderer/drawers/Provider"; import { shallowAccountsSelector } from "~/renderer/reducers/accounts"; import { trackSwapError, useGetSwapTrackingProperties } from "../utils/index"; import ExchangeDrawer from "./ExchangeDrawer/index"; -import FormLoading from "./FormLoading"; -import FormNotAvailable from "./FormNotAvailable"; import SwapFormSelectors from "./FormSelectors"; import SwapFormSummary from "./FormSummary"; import SwapFormRates from "./FormRates"; @@ -44,6 +36,7 @@ import { AccountLike } from "@ledgerhq/types-live"; import BigNumber from "bignumber.js"; import { CryptoCurrency, TokenCurrency } from "@ledgerhq/types-cryptoassets"; import { SWAP_RATES_TIMEOUT } from "../../config"; +import { OnNoRatesCallback } from "@ledgerhq/live-common/exchange/swap/types"; const Wrapper = styled(Box).attrs({ p: 20, @@ -63,27 +56,6 @@ const Button = styled(ButtonBase)` justify-content: center; `; -export const useProviders = () => { - const dispatch = useDispatch(); - const { providers, error: providersError } = useSwapProviders(); - const storedProviders = useSelector(providersSelector); - useEffect(() => { - if (providers) dispatch(updateProvidersAction(providers)); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [providers]); - - useEffect(() => { - if (providersError) dispatch(resetSwapAction()); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [providersError]); - - return { - storedProviders, - providers, - providersError, - }; -}; - const SwapForm = () => { const swapDefaultTrack = useGetSwapTrackingProperties(); const [idleState, setIdleState] = useState(false); @@ -92,18 +64,17 @@ const SwapForm = () => { const { state: locationState } = useLocation(); const history = useHistory(); const accounts = useSelector(shallowAccountsSelector); - const { storedProviders, providersError } = useProviders(); const exchangeRate = useSelector(rateSelector); const walletApiPartnerList = useFeature("swapWalletApiPartnerList"); - const setExchangeRate = useCallback( + const setExchangeRate: SetExchangeRateCallback = useCallback( rate => { dispatch(updateRateAction(rate)); }, [dispatch], ); - const onNoRates = useCallback( + const onNoRates: OnNoRatesCallback = useCallback( ({ toState }) => { track("error_message", { message: "no_rates", @@ -120,11 +91,14 @@ const SwapForm = () => { setExchangeRate, onNoRates, ...(locationState as object), - providers: storedProviders || undefined, timeout: SWAP_RATES_TIMEOUT, timeoutErrorMessage: t("swap2.form.timeout.message"), }); + const isSwapLiveAppEnabled = useIsSwapLiveApp({ + currencyFrom: swapTransaction.swap.from.currency, + }); + // @TODO: Try to check if we can directly have the right state from `useSwapTransaction` // Used to set the fake transaction recipient // As of today, we need to call setFromAccount to trigger an updateTransaction @@ -160,10 +134,7 @@ const SwapForm = () => { }, [idleState]); const swapWebAppRedirection = useCallback(async () => { - const { - swap, - status: { estimatedFees: initFeeTotalValue }, - } = swapTransaction; + const { swap } = swapTransaction; const { to, from } = swap; const transaction = swapTransaction.transaction; const { account: fromAccount, parentAccount: fromParentAccount } = from; @@ -175,9 +146,11 @@ const SwapForm = () => { const toAccountId = accountToWalletAPIAccount(toAccount, toParentAccount)?.id; const fromAmount = convertToNonAtomicUnit(transaction?.amount, fromAccount); - const customFeeConfig = - feesStrategy === "custom" ? getCustomFeesPerFamily(transaction) : null; - + const customFeeConfig = getCustomFeesPerFamily(transaction); + // The Swap web app will automatically recreate the transaction with "default" fees. + // However, if you wish to use a different fee type, you will need to set it as custom. + const isCustomFee = + feesStrategy === "slow" || feesStrategy === "fast" || feesStrategy === "custom"; history.push({ pathname: "/swap-web", state: { @@ -187,9 +160,8 @@ const SwapForm = () => { fromAmount, quoteId: rateId ? rateId : undefined, rate, - feeStrategy: feesStrategy?.toUpperCase(), + feeStrategy: (isCustomFee ? "custom" : "medium")?.toUpperCase(), customFeeConfig: customFeeConfig ? JSON.stringify(customFeeConfig) : undefined, - initFeeTotalValue, }, }); } @@ -233,7 +205,6 @@ const SwapForm = () => { !swapTransaction.bridgePending && exchangeRatesState.status !== "loading" && swapTransaction.transaction && - !providersError && !swapError && exchangeRate && swapTransaction.swap.to.account && @@ -256,14 +227,7 @@ const SwapForm = () => { if (providerType === "DEX") { const from = swapTransaction.swap.from; const fromAccountId = from.parentAccount?.id || from.account?.id; - const customParams = { - provider, - providerURL, - } as { - provider: string; - providerURL?: string; - }; - const customDappUrl = getCustomDappUrl(customParams); + const pathname = `/platform/${getProviderName(provider).toLowerCase()}`; const getAccountId = ({ accountId, @@ -291,7 +255,7 @@ const SwapForm = () => { // This looks like an issue, the proper signature is: push(path, [state]) - (function) Pushes a new entry onto the history stack // It seems possible to also pass a LocationDescriptorObject but it does not expect extra properties // @ts-expect-error so customDappUrl is not expected to be here - customDappUrl, + customDappUrl: providerURL, pathname, state: { returnTo: "/swap", @@ -299,8 +263,7 @@ const SwapForm = () => { }, }); } else { - const swapWebApp = !!process.env.SWAP_WEB_APP; - if (swapWebApp) { + if (isSwapLiveAppEnabled) { swapWebAppRedirection(); } else { setDrawer( @@ -323,8 +286,6 @@ const SwapForm = () => { useEffect(() => { if (!exchangeRate) { - // @ts-expect-error This seems like a mistake? updateSelectedRate expects an ExchangeRate - swapTransaction.swap.updateSelectedRate({}); return; } swapTransaction.swap.updateSelectedRate(exchangeRate); @@ -348,68 +309,56 @@ const SwapForm = () => { swapTransaction.toggleMax(); }; - if (storedProviders?.length) { - return ( - - - - {pageState === "empty" && } - {pageState === "loading" && } - {pageState === "initial" && ( - - - - )} - - {pageState === "loaded" && ( - <> - - - - )} - - - - - - ); - } - - // TODO: ensure that the error is catch by Sentry in this case - if (storedProviders?.length === 0 || providersError) { - return ( - <> - - - ); - } - return ; + return ( + + + + {pageState === "empty" && } + {pageState === "loading" && } + {pageState === "initial" && ( + + + + )} + + {pageState === "loaded" && ( + <> + + + + )} + + + + + + ); }; export default SwapForm; diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/History/History.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/History/History.tsx index d52b7d396b45..b85a395dcd79 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/History/History.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/Swap2/History/History.tsx @@ -8,7 +8,7 @@ import OperationRow from "./OperationRow"; import { isSwapOperationPending } from "@ledgerhq/live-common/exchange/swap/index"; import getCompleteSwapHistory from "@ledgerhq/live-common/exchange/swap/getCompleteSwapHistory"; import updateAccountSwapStatus from "@ledgerhq/live-common/exchange/swap/updateAccountSwapStatus"; -import { SwapHistorySection } from "@ledgerhq/live-common/exchange/swap/types"; +import { MappedSwapOperation, SwapHistorySection } from "@ledgerhq/live-common/exchange/swap/types"; import { flattenAccounts } from "@ledgerhq/live-common/account/index"; import { mappedSwapOperationsToCSV } from "@ledgerhq/live-common/exchange/swap/csvExport"; import { updateAccountWithUpdater } from "~/renderer/actions/accounts"; @@ -145,7 +145,7 @@ const History = () => { } }, 10000); const openSwapOperationDetailsModal = useCallback( - mappedSwapOperation => + (mappedSwapOperation: MappedSwapOperation) => setDrawer(SwapOperationDetails, { mappedSwapOperation, }), diff --git a/apps/ledger-live-desktop/src/renderer/screens/exchange/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/exchange/index.tsx index cd2ea5d01fc1..a2cc6363fba3 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/exchange/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/exchange/index.tsx @@ -1,17 +1,22 @@ -import React from "react"; +import React, { useMemo } from "react"; +import semver from "semver"; import { RouteComponentProps, useLocation } from "react-router-dom"; import { useSelector } from "react-redux"; import { RampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/types"; import Card from "~/renderer/components/Box/Card"; import { languageSelector } from "~/renderer/reducers/settings"; +import { accountsSelector } from "~/renderer/reducers/accounts"; import { useRemoteLiveAppManifest } from "@ledgerhq/live-common/platform/providers/RemoteLiveAppProvider/index"; import useTheme from "~/renderer/hooks/useTheme"; import { useLocalLiveAppManifest } from "@ledgerhq/live-common/platform/providers/LocalLiveAppProvider/index"; import WebPTXPlayer from "~/renderer/components/WebPTXPlayer"; +import { getParentAccount, isTokenAccount } from "@ledgerhq/live-common/account/index"; import { LiveAppManifest, Loadable } from "@ledgerhq/live-common/platform/types"; +import { accountToWalletAPIAccount } from "@ledgerhq/live-common/wallet-api/converters"; import { DEFAULT_MULTIBUY_APP_ID, INTERNAL_APP_IDS, + WALLET_API_VERSION, } from "@ledgerhq/live-common/wallet-api/constants"; export type DProps = { @@ -20,10 +25,14 @@ export type DProps = { defaultTicker?: string | null; rampCatalog: Loadable; }; + +type ExchangeState = { account?: string } | undefined; + const LiveAppExchange = ({ appId }: { appId: string }) => { - const { state: urlParams, search } = useLocation(); + const { state: urlParams, search } = useLocation(); const searchParams = new URLSearchParams(search); const locale = useSelector(languageSelector); + const accounts = useSelector(accountsSelector); const mockManifest: LiveAppManifest | undefined = process.env.MOCK_REMOTE_LIVE_MANIFEST && JSON.parse(process.env.MOCK_REMOTE_LIVE_MANIFEST)[0]; @@ -33,6 +42,28 @@ const LiveAppExchange = ({ appId }: { appId: string }) => { const manifest = localManifest || mockManifest || remoteManifest; const themeType = useTheme().colors.palette.type; + /** + * Pass correct account ID + * Due to Platform SDK account ID not being equivalent to Wallet API account ID + */ + const customUrlParams = useMemo(() => { + if ( + urlParams?.account && + manifest?.apiVersion && + semver.satisfies(WALLET_API_VERSION, manifest.apiVersion) + ) { + const { account: accountId } = urlParams; + const account = accounts.find(a => a.id === accountId); + if (account) { + const parentAccount = isTokenAccount(account) + ? getParentAccount(account, accounts) + : undefined; + urlParams.account = accountToWalletAPIAccount(account, parentAccount).id; + } + } + return urlParams; + }, [accounts, manifest?.apiVersion, urlParams]); + /** * Given the user is on an internal app (webview url is owned by LL) we must reset the session * to ensure the context is reset. last-screen is used to give an external app's webview context @@ -57,7 +88,7 @@ const LiveAppExchange = ({ appId }: { appId: string }) => { manifest={manifest} inputs={{ theme: themeType, - ...(urlParams as object), + ...customUrlParams, lang: locale, ...Object.fromEntries(searchParams.entries()), }} diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/AppsList.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/AppsList.tsx index e202be9250a7..95f91accb893 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/AppsList.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/AppsList.tsx @@ -24,6 +24,7 @@ import SearchBox from "../../accounts/AccountList/SearchBox"; import { App } from "@ledgerhq/types-live"; import { AppType, SortOptions } from "@ledgerhq/live-common/apps/filtering"; import NoResults from "~/renderer/icons/NoResults"; +import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets"; // sticky top bar with extra width to cover card boxshadow underneath export const StickyTabBar = styled.div` @@ -106,7 +107,7 @@ const AppsList = ({ }, [search]); const { installed: installedApps, uninstallQueue, apps } = state; const addAccount = useCallback( - currency => { + (currency?: CryptoOrTokenCurrency) => { push("/accounts"); reduxDispatch( openModal("MODAL_ADD_ACCOUNTS", { diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/Filter.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/Filter.tsx index 14e430dac0c6..0ac1fcbc8aad 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/Filter.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/AppsList/Filter.tsx @@ -14,13 +14,6 @@ type Props = { }; const Filter = ({ onFilterChange, filter }: Props) => { - const onFilterChangeWrapper = useCallback( - item => { - if (!item) return; - onFilterChange(item.key); - }, - [onFilterChange], - ); const filterItems = [ { key: "all", @@ -39,8 +32,17 @@ const Filter = ({ onFilterChange, filter }: Props) => { label: , }, ]; + + const onFilterChangeWrapper = useCallback( + (item: (typeof filterItems)[number]) => { + if (!item) return; + onFilterChange(item.key); + }, + [onFilterChange], + ); + const renderItem = useCallback( - ({ item, isActive }) => ( + ({ item, isActive }: { item: (typeof filterItems)[number]; isActive: boolean }) => ( { - const onSortChangeWrapper = useCallback( - item => { - if (!item) { - return; - } - onSortChange(item.sort); - }, - [onSortChange], - ); const sortItems = [ { key: "marketcap_desc", @@ -49,8 +40,18 @@ const Sort = ({ onSortChange, sort }: Props) => { label: , }, ]; + const onSortChangeWrapper = useCallback( + (item: (typeof sortItems)[number]) => { + if (!item) { + return; + } + onSortChange(item.sort); + }, + [onSortChange], + ); + const renderItem = useCallback( - ({ item, isActive }) => ( + ({ item, isActive }: { item: (typeof sortItems)[number]; isActive: boolean }) => ( 0; const updateProgress = updateAllProgress(state); const onUpdateAll = useCallback( - e => { + (e: SyntheticEvent) => { if (open) e.stopPropagation(); dispatch({ type: "updateAll", @@ -160,7 +160,7 @@ const UpdateAllApps = ({ update, state, optimisticState, dispatch, isIncomplete ); const mapApp = useCallback( - (app, i) => ( + (app: App, i: number) => ( { }, []); const onRemove = useCallback(() => { - setDrawer(RemoveCustomImage); + setDrawer<{ onClose?: () => void }>(RemoveCustomImage); }, []); return ( diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/DeviceLanguageInstallation.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/DeviceLanguageInstallation.tsx index eeddb2c3da58..d85ee8889a55 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/DeviceLanguageInstallation.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/DeviceLanguageInstallation.tsx @@ -71,7 +71,7 @@ const DeviceLanguageInstallation: React.FC = ({ }, [setInstalling, selectedLanguage]); const onWrappedError = useCallback( - error => { + (error: Error) => { setError(error); onError(error); }, diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/RemoveCustomImage.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/RemoveCustomImage.tsx index 0e8c395542a6..159dd4e541b6 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/RemoveCustomImage.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/DeviceStorage/RemoveCustomImage.tsx @@ -18,7 +18,9 @@ const TextEllipsis = styled.div` text-overflow: ellipsis; `; -const RemoveCustomImage: React.FC<{ onClose?: () => void }> = ({ onClose }) => { +type Props = { onClose?: () => void }; + +const RemoveCustomImage: React.FC = ({ onClose }) => { const request = useMemo(() => ({}), []); const { t } = useTranslation(); const dispatch = useDispatch(); @@ -41,7 +43,7 @@ const RemoveCustomImage: React.FC<{ onClose?: () => void }> = ({ onClose }) => { }, [dispatch]); const onError = useCallback( - error => { + (error: Error) => { setError(error); if (error instanceof ImageDoesNotExistOnDevice) { dispatch(clearLastSeenCustomImage()); diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/FirmwareUpdate/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/FirmwareUpdate/index.tsx index ddd169253fab..ce1101c640fb 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/FirmwareUpdate/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/FirmwareUpdate/index.tsx @@ -101,6 +101,7 @@ const FirmwareUpdate = (props: Props) => { device.modelId, ), onDrawerClose, + onRequestClose, status: modal, stepId: stepId, installed: installed, @@ -116,7 +117,8 @@ const FirmwareUpdate = (props: Props) => { setDrawer(UpdateModal, updateModalProps, { preventBackdropClick: true, forceDisableFocusTrap: true, - onRequestClose, + onRequestClose: undefined, + withPaddingTop: false, }); }, [ device, diff --git a/apps/ledger-live-desktop/src/renderer/screens/manager/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/manager/index.tsx index 390605a1d5ec..954e7611c4be 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/manager/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/manager/index.tsx @@ -16,13 +16,13 @@ import { context } from "~/renderer/drawers/Provider"; const action = createAction(getEnv("MOCK") ? mockedEventEmitter : connectManager); const Manager = () => { - const [appsToRestore, setRestoreApps] = useState([]); + const [appsToRestore, setRestoreApps] = useState([]); const { setDrawer } = useContext(context); const [result, setResult] = useState(null); const [hasReset, setHasReset] = useState(false); const onReset = useCallback( - (apps, firmwareUpdateOpened) => { - setRestoreApps(apps); + (apps?: string[] | null, firmwareUpdateOpened?: boolean | null) => { + setRestoreApps(apps ?? []); setResult(null); setDrawer(); // Nb prevent zombie flows. if (!firmwareUpdateOpened) setHasReset(true); @@ -47,7 +47,7 @@ const Manager = () => { }); } }, [result, dispatch]); - const onResult = useCallback(result => setResult(result), []); + const onResult = useCallback((result: Result) => setResult(result), []); return ( <> diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx index d6ce18aeeb9e..29c3951a5a24 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/CountervalueSelect.tsx @@ -1,5 +1,5 @@ import React, { useCallback, useMemo, memo } from "react"; -import { supportedCountervalues, SupportedCoutervaluesData } from "~/renderer/reducers/settings"; +import { supportedCountervalues, SupportedCountervaluesData } from "~/renderer/reducers/settings"; import Dropdown from "./DropDown"; import Track from "~/renderer/analytics/Track"; import { useTranslation } from "react-i18next"; @@ -29,7 +29,7 @@ function CounterValueSelect({ const options = useMemo( () => - supportedCountervalues.filter(({ value }: SupportedCoutervaluesData) => + supportedCountervalues.filter(({ value }: SupportedCountervaluesData) => supportedCounterCurrencies.includes(value?.toLowerCase()), ), [supportedCounterCurrencies], @@ -38,7 +38,7 @@ function CounterValueSelect({ const cvOption = useMemo( () => supportedCountervalues.find( - (f: SupportedCoutervaluesData) => + (f: SupportedCountervaluesData) => f?.value?.toLowerCase() === counterCurrency?.toLowerCase(), ), [counterCurrency], diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/MarketCoinChart.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/MarketCoinChart.tsx index 7fdd94896927..856b80aae801 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/MarketCoinChart.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/MarketCoinChart.tsx @@ -113,7 +113,7 @@ function MarkeCoinChartComponent({ }, [chartData, range]); const setRange = useCallback( - index => { + (index: number) => { const newRange = ranges[index]; if (range !== newRange) refreshChart({ range: newRange }); }, diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/index.tsx index c0ffc2a1c5ba..1523da9740ed 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/MarketCoinScreen/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from "react"; +import React, { useCallback } from "react"; import { Flex, Text, Icon } from "@ledgerhq/react-ui"; import { useSelector, useDispatch } from "react-redux"; import { useHistory, useParams } from "react-router-dom"; @@ -15,16 +15,15 @@ import { useGetSwapTrackingProperties } from "~/renderer/screens/exchange/Swap2/ import { Button } from ".."; import MarketCoinChart from "./MarketCoinChart"; import MarketInfo from "./MarketInfo"; -import { useProviders } from "../../exchange/Swap2/Form"; import { getAvailableAccountsById } from "@ledgerhq/live-common/exchange/swap/utils/index"; import { accountsSelector } from "~/renderer/reducers/accounts"; import { openModal } from "~/renderer/actions/modals"; -import { getAllSupportedCryptoCurrencyTickers } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; import { flattenAccounts } from "@ledgerhq/live-common/account/index"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import useStakeFlow from "../../stake"; import { stakeDefaultTrack } from "~/renderer/screens/stake/constants"; +import { useFetchCurrencyAll } from "@ledgerhq/live-common/exchange/swap/hooks/index"; const CryptoCurrencyIconWrapper = styled.div` height: 56px; @@ -67,16 +66,8 @@ export default function MarketCoinScreen() { const locale = useSelector(localeSelector); const allAccounts = useSelector(accountsSelector); const flattenedAccounts = flattenAccounts(allAccounts); - const { providers, storedProviders } = useProviders(); const swapDefaultTrack = useGetSwapTrackingProperties(); - - const swapAvailableIds = useMemo(() => { - return providers || storedProviders - ? (providers || storedProviders)! - .map(({ pairs }) => pairs.map(({ from, to }) => [from, to])) - .flat(2) - : []; - }, [providers, storedProviders]); + const { data: currenciesAll } = useFetchCurrencyAll(); const { selectedCoinData: currency, @@ -89,8 +80,6 @@ export default function MarketCoinScreen() { supportedCounterCurrencies, } = useSingleCoinMarketData(); - const rampCatalog = useRampCatalog(); - const { id, ticker, @@ -115,16 +104,12 @@ export default function MarketCoinScreen() { chartData, } = currency || {}; - const onRampAvailableTickers = useMemo(() => { - if (!rampCatalog.value) { - return []; - } - return getAllSupportedCryptoCurrencyTickers(rampCatalog.value.onRamp); - }, [rampCatalog.value]); + const { isCurrencyAvailable } = useRampCatalog(); + + const availableOnBuy = !!currency && isCurrencyAvailable(currency.id, "onRamp"); + + const availableOnSwap = internalCurrency && currenciesAll.includes(internalCurrency.id); - const availableOnBuy = - currency && currency.ticker && onRampAvailableTickers.includes(currency.ticker?.toUpperCase()); - const availableOnSwap = internalCurrency && swapAvailableIds.includes(internalCurrency.id); const stakeProgramsFeatureFlag = useFeature("stakePrograms"); const listFlag = stakeProgramsFeatureFlag?.params?.list ?? []; const stakeProgramsEnabled = stakeProgramsFeatureFlag?.enabled ?? false; diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/MarketList.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/MarketList.tsx index 515c6150421d..681121480678 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/MarketList.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/MarketList.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, memo, useMemo } from "react"; +import React, { useCallback, memo } from "react"; import { useMarketData } from "@ledgerhq/live-common/market/MarketDataProvider"; import styled, { DefaultTheme, StyledComponent } from "styled-components"; import { Flex, Text, Icon } from "@ledgerhq/react-ui"; @@ -13,16 +13,15 @@ import { Button } from "."; import { useSelector, useDispatch } from "react-redux"; import { localeSelector } from "~/renderer/reducers/settings"; import { addStarredMarketCoins, removeStarredMarketCoins } from "~/renderer/actions/settings"; -import { useProviders } from "../exchange/Swap2/Form"; import Track from "~/renderer/analytics/Track"; -import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/index"; -import { getAllSupportedCryptoCurrencyTickers } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/helpers"; +import { useRampCatalog } from "@ledgerhq/live-common/platform/providers/RampCatalogProvider/useRampCatalog"; import Image from "~/renderer/components/Image"; import NoResultsFound from "~/renderer/images/no-results-found.png"; import { useFeature } from "@ledgerhq/live-common/featureFlags/index"; import { FlexProps } from "styled-system"; import { CurrencyData, MarketListRequestParams } from "@ledgerhq/live-common/market/types"; import TrackPage from "~/renderer/analytics/TrackPage"; +import { useFetchCurrencyFrom } from "@ledgerhq/live-common/exchange/swap/hooks/index"; export const TableCellBase: StyledComponent<"div", DefaultTheme, FlexProps> = styled(Flex).attrs({ alignItems: "center", @@ -225,10 +224,9 @@ const CurrencyRow = memo(function CurrencyRowItem({ starredMarketCoins, locale, swapAvailableIds, - onRampAvailableTickers, style, }: { - data: CurrencyData[]; + data: CurrencyData[]; // NB: CurrencyData.id is different to Currency.id index: number; counterCurrency?: string; loading: boolean; @@ -237,14 +235,20 @@ const CurrencyRow = memo(function CurrencyRowItem({ starredMarketCoins: string[]; locale: string; swapAvailableIds: string[]; - onRampAvailableTickers: string[]; range?: string; style: React.CSSProperties; }) { const currency = data ? data[index] : null; const internalCurrency = currency ? currency.internalCurrency : null; const isStarred = currency && starredMarketCoins.includes(currency.id); - const availableOnBuy = currency && onRampAvailableTickers.includes(currency.ticker.toUpperCase()); + + const { isCurrencyAvailable } = useRampCatalog(); + + const availableOnBuy = + !!internalCurrency && + !!internalCurrency?.id && + isCurrencyAvailable(internalCurrency.id, "onRamp"); + const availableOnSwap = internalCurrency && swapAvailableIds.includes(internalCurrency.id); const stakeProgramsFeatureFlag = useFeature("stakePrograms"); const listFlag = stakeProgramsFeatureFlag?.params?.list ?? []; @@ -279,22 +283,6 @@ function MarketList({ }) { const { t } = useTranslation(); const locale = useSelector(localeSelector); - const { providers, storedProviders } = useProviders(); - const rampCatalog = useRampCatalog(); - - const onRampAvailableTickers = useMemo(() => { - if (!rampCatalog.value) { - return []; - } - return getAllSupportedCryptoCurrencyTickers(rampCatalog.value.onRamp); - }, [rampCatalog.value]); - - const swapAvailableIds = - providers || storedProviders - ? (providers || storedProviders)! - .map(({ pairs }) => pairs.map(({ from, to }) => [from, to])) - .flat(2) - : []; const { marketData = [], @@ -312,10 +300,12 @@ function MarketList({ const currenciesLength = marketData.length; const freshLoading = loading && !currenciesLength; + const { data: fromCurrencies } = useFetchCurrencyFrom(); + const resetSearch = useCallback(() => refresh({ search: "" }), [refresh]); const toggleStar = useCallback( - (id, isStarred) => { + (id: string, isStarred: boolean) => { if (isStarred) { dispatch(removeStarredMarketCoins(id)); } else { @@ -326,7 +316,7 @@ function MarketList({ ); const toggleSortBy = useCallback( - newOrderBy => { + (newOrderBy: string) => { const isFreshSort = newOrderBy !== orderBy; refresh( isFreshSort @@ -396,8 +386,7 @@ function MarketList({ selectCurrency={selectCurrency} starredMarketCoins={starredMarketCoins} locale={locale} - swapAvailableIds={swapAvailableIds} - onRampAvailableTickers={onRampAvailableTickers} + swapAvailableIds={fromCurrencies ?? []} range={range} /> )} @@ -436,8 +425,7 @@ function MarketList({ selectCurrency={selectCurrency} starredMarketCoins={starredMarketCoins} locale={locale} - swapAvailableIds={swapAvailableIds} - onRampAvailableTickers={onRampAvailableTickers} + swapAvailableIds={fromCurrencies ?? []} range={range} /> )} diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/SideDrawerFilter.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/SideDrawerFilter.tsx index ac6fd5e823e6..b0c31631d97b 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/SideDrawerFilter.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/SideDrawerFilter.tsx @@ -20,7 +20,7 @@ export default function SideDrawerFilter({ [refresh], ); const onChange = useCallback( - option => { + (option?: { label: string; value: string } | null) => { if (!option) return; switch (option.value) { case "all": diff --git a/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx b/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx index fed9658f6332..c0e90240fc99 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/market/index.tsx @@ -79,6 +79,7 @@ export default function Market() { ); const updateTimeRange = useCallback( + // @ts-expect-error i don't know how to type this Dropdown function ({ value }) => { refresh({ range: value }); }, @@ -137,6 +138,7 @@ export default function Market() { { [account, dispatch], ); const onOpenCollection = useCallback( - collectionAddress => history.push(`/account/${account.id}/nft-collection/${collectionAddress}`), + (collectionAddress: string) => + history.push(`/account/${account.id}/nft-collection/${collectionAddress}`), [account.id, history], ); const collections = useMemo(() => nftsByCollections(account.nfts), [account.nfts]); diff --git a/apps/ledger-live-desktop/src/renderer/screens/nft/Gallery/Gallery.tsx b/apps/ledger-live-desktop/src/renderer/screens/nft/Gallery/Gallery.tsx index 483d864fbed9..4f40fbb1e8c0 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/nft/Gallery/Gallery.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/nft/Gallery/Gallery.tsx @@ -77,7 +77,7 @@ const Gallery = () => { ); }, [dispatch, account]); const onSelectCollection = useCallback( - collectionAddress => { + (collectionAddress: string) => { history.push({ pathname: `/account/${account?.id}/nft-collection/${collectionAddress}`, }); diff --git a/apps/ledger-live-desktop/src/renderer/screens/nft/Send/SelectNFT.tsx b/apps/ledger-live-desktop/src/renderer/screens/nft/Send/SelectNFT.tsx index 2ebf865761fc..bda2aba57723 100644 --- a/apps/ledger-live-desktop/src/renderer/screens/nft/Send/SelectNFT.tsx +++ b/apps/ledger-live-desktop/src/renderer/screens/nft/Send/SelectNFT.tsx @@ -16,7 +16,8 @@ const SelectNFT = ({ maybeNFTCollection?: string; account: Account; }) => { - const [token, setToken] = useState(null); + const [token, setToken] = useState(null); + // @ts-expect-error impossible to type this, we need to bump react-select to v5 const getOptionValue = useCallback(item => item, []); const hiddenNftCollections = useSelector(hiddenNftCollectionsSelector); const filteredNFTs = useMemo( @@ -29,7 +30,7 @@ const SelectNFT = ({ [maybeNFTCollection, account.nfts, account.id, hiddenNftCollections], ); const onTokenSelected = useCallback( - token => { + (token: ProtoNFT | NFT) => { onSelect(token); setToken(token); }, @@ -51,6 +52,7 @@ const SelectNFT = ({ return (