Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: fix ledger popups on send flow #1960

Merged
merged 17 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions packages/desktop/components/popup/Popup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import DappAccountSwitcherPopup from './popups/DappAccountSwitcherPopup.svelte'
import DeepLinkErrorPopup from './popups/DeepLinkErrorPopup.svelte'
import DiagnosticsPopup from './popups/DiagnosticsPopup.svelte'
import EnableLedgerBlindSigningPopup from './popups/EnableLedgerBlindSigningPopup.svelte'
import ErrorLogPopup from './popups/ErrorLogPopup.svelte'
import EvmTransactionFromDappPopup from './popups/EvmTransactionFromDappPopup.svelte'
import FaucetRequestPopup from './popups/FaucetRequestPopup.svelte'
Expand Down Expand Up @@ -61,7 +60,6 @@
import TestDeepLinkFormPopup from './popups/TestDeepLinkFormPopup.svelte'
import TokenInformationPopup from './popups/TokenInformationPopup.svelte'
import UnlockStrongholdPopup from './popups/UnlockStrongholdPopup.svelte'
import VerifyLedgerTransactionPopup from './popups/VerifyLedgerTransactionPopup.svelte'
import VoteForProposal from './popups/VoteForProposalPopup.svelte'
import VotingPowerToZeroPopup from './popups/VotingPowerToZeroPopup.svelte'
import { localize } from '@core/i18n'
Expand Down Expand Up @@ -112,7 +110,6 @@
[PopupId.DappAccountSwitcher]: DappAccountSwitcherPopup,
[PopupId.DeepLinkError]: DeepLinkErrorPopup,
[PopupId.Diagnostics]: DiagnosticsPopup,
[PopupId.EnableLedgerBlindSigning]: EnableLedgerBlindSigningPopup,
[PopupId.ErrorLog]: ErrorLogPopup,
[PopupId.EvmTransactionFromDapp]: EvmTransactionFromDappPopup,
[PopupId.FaucetRequest]: FaucetRequestPopup,
Expand Down Expand Up @@ -141,7 +138,6 @@
[PopupId.TestDeepLinkForm]: TestDeepLinkFormPopup,
[PopupId.TokenInformation]: TokenInformationPopup,
[PopupId.UnlockStronghold]: UnlockStrongholdPopup,
[PopupId.VerifyLedgerTransaction]: VerifyLedgerTransactionPopup,
[PopupId.VoteForProposal]: VoteForProposal,
[PopupId.VotingPowerToZero]: VotingPowerToZeroPopup,
}
Expand Down
6 changes: 6 additions & 0 deletions packages/desktop/components/popup/ProfileAuthPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// Popups
import ConnectLedgerPopup from './profileAuthPopups/ConnectLedgerPopup.svelte'
import UnlockStrongholdPopup from './profileAuthPopups/UnlockStrongholdPopup.svelte'
import VerifyLedgerTransactionPopup from './profileAuthPopups/VerifyLedgerTransactionPopup.svelte'
import EnableLedgerBlindSigningPopup from './profileAuthPopups/EnableLedgerBlindSigningPopup.svelte'

export let id: ProfileAuthPopupId
export let props: any
Expand Down Expand Up @@ -40,6 +42,10 @@
<ConnectLedgerPopup {...props} />
{:else if id === ProfileAuthPopupId.UnlockStronghold}
<UnlockStrongholdPopup {...props} />
{:else if id === ProfileAuthPopupId.EnableLedgerBlindSigning}
<EnableLedgerBlindSigningPopup {...props} />
{:else if id === ProfileAuthPopupId.VerifyLedgerTransaction}
<VerifyLedgerTransactionPopup {...props} />
{/if}
{#if !hideClose}
<CloseButton on:click={tryClosePopup} size="sm" class="absolute top-8 right-8 p-2" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
import { localize } from '@core/i18n'
import { LedgerAppName, ledgerDeviceState } from '@core/ledger'
import { UiEventFunction } from '@core/utils'
import { closePopup } from '@desktop/auxiliary/popup'
import { closeProfileAuthPopup } from '@desktop/auxiliary/popup'
import PopupTemplate from '../PopupTemplate.svelte'

export let appName: LedgerAppName
export let onEnabled: UiEventFunction = () => {}
export let onClose: UiEventFunction = () => {}

const STEPS = [1, 2, 3, 4]

$: if ($ledgerDeviceState && $ledgerDeviceState.settings[appName]?.blindSigningEnabled) {
closePopup({ forceClose: true })
closeProfileAuthPopup({ forceClose: true })
onEnabled && onEnabled()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ export enum PopupId {
DeepLinkError = 'deepLinkError',
DappAccountSwitcher = 'dappAccountSwitcher',
Diagnostics = 'diagnostics',
EnableLedgerBlindSigning = 'enableLedgerBlindSigning',
ErrorLog = 'errorLog',
EvmTransactionFromDapp = 'EvmTransactionFromDapp',
FaucetRequest = 'faucetRequest',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export enum ProfileAuthPopupId {
ConnectLedger = 'connectLedger',
EnableLedgerBlindSigning = 'enableLedgerBlindSigning',
UnlockStronghold = 'unlockStronghold',
VerifyLedgerTransaction = 'verifyLedgerTransaction',
}
26 changes: 16 additions & 10 deletions packages/shared/src/lib/core/ledger/classes/ledger.class.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import {
import { Converter, MILLISECONDS_PER_SECOND, sleep } from '@core/utils'
import { TypedTxData } from '@ethereumjs/tx'
import type { Bip44 } from '@iota/sdk/out/types'
import { PopupId, closePopup, openPopup } from '../../../../../../desktop/lib/auxiliary/popup'
import {
ProfileAuthPopupId,
closeProfileAuthPopup,
openProfileAuthPopup,
} from '../../../../../../desktop/lib/auxiliary/popup'
import { DEFAULT_LEDGER_API_REQUEST_OPTIONS } from '../constants'
import { LedgerApiMethod, LedgerAppName } from '../enums'
import { ILedgerApiBridge } from '../interfaces'
Expand Down Expand Up @@ -79,8 +83,8 @@ export class Ledger {
await this.userEnablesBlindSigning()
}

openPopup({
id: PopupId.VerifyLedgerTransaction,
openProfileAuthPopup({
id: ProfileAuthPopupId.VerifyLedgerTransaction,
hideClose: true,
preventClose: true,
props: {
Expand All @@ -100,21 +104,21 @@ export class Ledger {
),
'evm-signed-transaction'
)
closeProfileAuthPopup({ forceClose: true })

if (transactionSignature) {
const { r, v, s } = transactionSignature
if (r && v && s) {
return prepareEvmTransaction(transactionData, chainId, { r, v, s })
} else {
closePopup({ forceClose: true })
throw new Error(localize('error.ledger.rejected'))
}
}
}

static async signMessage(rawMessage: string, bip44: Bip44): Promise<string | undefined> {
openPopup({
id: PopupId.VerifyLedgerTransaction,
openProfileAuthPopup({
id: ProfileAuthPopupId.VerifyLedgerTransaction,
hideClose: true,
preventClose: true,
props: {
Expand All @@ -129,6 +133,7 @@ export class Ledger {
() => ledgerApiBridge.makeRequest(LedgerApiMethod.SignMessage, messageHex, bip32Path),
'signed-message'
)
closeProfileAuthPopup({ forceClose: true })

const { r, v, s } = transactionSignature
if (r && v && s) {
Expand All @@ -147,8 +152,8 @@ export class Ledger {
version: SignTypedDataVersion.V3 | SignTypedDataVersion.V4
): Promise<string | undefined> {
const rawMessage = JSON.parse(jsonString)
openPopup({
id: PopupId.VerifyLedgerTransaction,
openProfileAuthPopup({
id: ProfileAuthPopupId.VerifyLedgerTransaction,
hideClose: true,
preventClose: true,
props: {
Expand All @@ -173,6 +178,7 @@ export class Ledger {
() => ledgerApiBridge.makeRequest(LedgerApiMethod.SignEIP712, hashedDomain, hashedMessage, bip32Path),
'signed-eip712'
)
closeProfileAuthPopup({ forceClose: true })

const { r, v, s } = transactionSignature
if (r && v && s) {
Expand Down Expand Up @@ -219,8 +225,8 @@ export class Ledger {
private static userEnablesBlindSigning(): Promise<void> {
return new Promise((resolve, reject) => {
let isDisabled = true
openPopup({
id: PopupId.EnableLedgerBlindSigning,
openProfileAuthPopup({
id: ProfileAuthPopupId.EnableLedgerBlindSigning,
props: {
appName: LedgerAppName.Ethereum,
onEnabled: () => {
Expand Down
101 changes: 53 additions & 48 deletions packages/shared/src/lib/core/ledger/utils/handleLedgerError.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,69 +5,74 @@ import { resetMintTokenDetails, resetMintNftDetails } from '@core/wallet/stores'
import { IError } from '@core/error/interfaces'
import { handleError, handleGenericError } from '@core/error/handlers'
import { showNotification } from '@auxiliary/notification'
import { closePopup, openPopup, PopupId, popupState } from '../../../../../../desktop/lib/auxiliary/popup'
import {
closeProfileAuthPopup,
openProfileAuthPopup,
profileAuthPopup,
ProfileAuthPopupId,
} from '../../../../../../desktop/lib/auxiliary/popup'

import { LEDGER_ERROR_LOCALES } from '../constants'
import { LedgerAppName, LedgerError } from '../enums'
import { deriveLedgerError } from '../helpers'
import { checkOrConnectLedger, ledgerPreparedOutput, resetLedgerPreparedOutput } from '@core/ledger'
import { checkOrConnectLedgerAsync, ledgerPreparedOutput, resetLedgerPreparedOutput } from '@core/ledger'
import { sendOutput } from '@core/wallet'
import { activeProfile } from '@core/profile/stores'
import { SupportedNetworkId } from '@core/network/enums'

export function handleLedgerError(error: IError, resetConfirmationPropsOnDenial = true): void {
const ledgerError = deriveLedgerError(error?.error)
if (ledgerError in LEDGER_ERROR_LOCALES) {
const popupType = get(popupState)?.id
if (!ledgerError || !(ledgerError in LEDGER_ERROR_LOCALES)) {
handleGenericError(error)
return
}

const wasDeniedByUser = ledgerError === LedgerError.DeniedByUser
const popupType = get(profileAuthPopup)?.id

/**
* NOTE: We may wish to reset the confirmation props to avoid
* re-opening the popup if the user manually rejected the prompt
* on the device.
*/
if (wasDeniedByUser && resetConfirmationPropsOnDenial) {
resetMintTokenDetails()
resetMintNftDetails()
}
const wasDeniedByUser = ledgerError === LedgerError.DeniedByUser

closePopup({ forceClose: true })
/**
* NOTE: We may wish to reset the confirmation props to avoid
* re-opening the popup if the user manually rejected the prompt
* on the device.
*/
if (wasDeniedByUser && resetConfirmationPropsOnDenial) {
resetMintTokenDetails()
resetMintNftDetails()
}

/**
* NOTE: Because the device has a warning prompt about blind signing when trying it
* while it's disabled, the user has to manually reject it on the device. This results in
* an error, however it is bad UX to display it to the user when they meant to do it.
*/
const hadToEnableBlindSinging = popupType === PopupId.EnableLedgerBlindSigning && wasDeniedByUser
if (hadToEnableBlindSinging) {
const appName =
get(activeProfile)?.network?.id === SupportedNetworkId.Iota ? LedgerAppName.Iota : LedgerAppName.Shimmer
openPopup({
id: PopupId.EnableLedgerBlindSigning,
props: {
appName,
onEnabled: () => {
checkOrConnectLedger(async () => {
try {
if (get(ledgerPreparedOutput)) {
await sendOutput(get(ledgerPreparedOutput))
resetLedgerPreparedOutput()
}
} catch (err) {
handleError(err)
}
})
},
closeProfileAuthPopup({ forceClose: true })

/**
* NOTE: Because the device has a warning prompt about blind signing when trying it
* while it's disabled, the user has to manually reject it on the device. This results in
* an error, however it is bad UX to display it to the user when they meant to do it.
*/
const hadToEnableBlindSinging = popupType === ProfileAuthPopupId.EnableLedgerBlindSigning && wasDeniedByUser
if (hadToEnableBlindSinging) {
const appName =
get(activeProfile)?.network?.id === SupportedNetworkId.Iota ? LedgerAppName.Iota : LedgerAppName.Shimmer
openProfileAuthPopup({
id: ProfileAuthPopupId.EnableLedgerBlindSigning,
props: {
appName,
onEnabled: async () => {
try {
await checkOrConnectLedgerAsync()
if (get(ledgerPreparedOutput)) {
await sendOutput(get(ledgerPreparedOutput))
resetLedgerPreparedOutput()
}
} catch (err) {
handleError(err)
}
},
})
} else {
showNotification({
variant: wasDeniedByUser ? 'warning' : 'error',
text: localize(LEDGER_ERROR_LOCALES[ledgerError]),
})
}
},
})
} else {
handleGenericError(error)
showNotification({
variant: wasDeniedByUser ? 'warning' : 'error',
text: localize(LEDGER_ERROR_LOCALES[ledgerError]),
})
}
}
Loading
Loading