Skip to content

Commit

Permalink
feat: handle pairing expiry for wallet connect pairing flow (#2641)
Browse files Browse the repository at this point in the history
* cleanup confirmConnection drawer

* init supported namespace if not persisted

* show selections on edit click

* update namespace on selection change

* cleanup types

* improve buttons on confirm connection

* disable back

* skip connectionrequest drawer

* update type

* cleanup confirmation buttons

* add expiry time banner

* add locale

* refactor and use expiration component on connection request draw also

* fix: double button

---------

Co-authored-by: Nicole O'Brien <[email protected]>
  • Loading branch information
MarkNerdi and nicole-obrien authored Jun 20, 2024
1 parent c33ee91 commit 0b99994
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { Text } from '@bloomwalletio/ui'
import { time } from '@core/app/stores'
import { MILLISECONDS_PER_SECOND, SECONDS_PER_MINUTE } from '@core/utils/constants'
import { localize } from '@core/i18n'
import { getTimeDifference } from '@core/utils'
export let expiryTimestamp: number | undefined
const localeKey = 'views.dashboard.drawers.dapps.confirmConnection'
const expiryTimeDiff = (expiryTimestamp ?? 0) - $time.getTime() / MILLISECONDS_PER_SECOND
</script>

{#if expiryTimeDiff <= 0}
<div class="w-full flex gap-4 px-6 py-1 bg-danger/10">
<Text type="sm" textColor="danger" class="flex items-center">{localize(`${localeKey}.expired`)}</Text>
</div>
{:else}
<div
class="
w-full flex justify-between gap-4 px-6 py-1
{expiryTimeDiff < SECONDS_PER_MINUTE ? 'bg-warning/10' : 'bg-neutral/10'}
"
>
<Text
type="sm"
class="flex items-center"
textColor={expiryTimeDiff < SECONDS_PER_MINUTE ? 'warning' : 'primary'}
>
{localize(`${localeKey}.expiresIn`)}
{getTimeDifference(new Date((expiryTimestamp ?? 0) * MILLISECONDS_PER_SECOND), $time, true)}
</Text>
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { default as AccountSelection } from './AccountSelection.svelte'
export { default as ConnectionRequestExpirationAlert } from './ConnectionRequestExpirationAlert.svelte'
export { default as ConnectionSummary } from './ConnectionSummary.svelte'
export { default as DappCard } from './DappCard.svelte'
export { default as EditSelectionDrawer } from './EditSelectionDrawer.svelte'
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,31 @@
<script lang="ts">
import { Button, Spinner } from '@bloomwalletio/ui'
import { DappInfo } from '@ui'
import { localize } from '@core/i18n'
import { Router } from '@core/router'
import { DrawerTemplate } from '@components'
import { buildSupportedNamespacesFromSelections, connectToDapp } from '@auxiliary/wallet-connect/actions'
import { ALL_SUPPORTED_METHODS, SUPPORTED_EVENTS } from '@auxiliary/wallet-connect/constants'
import { DappVerification } from '@auxiliary/wallet-connect/enums'
import { getPersistedDappNamespacesForDapp, sessionProposal } from '@auxiliary/wallet-connect/stores'
import { ISupportedNamespace, SupportedNamespaces } from '@auxiliary/wallet-connect/types'
import { getCaip10AddressForAccount, rejectSession } from '@auxiliary/wallet-connect/utils'
import { AccountSelection, ConnectionSummary, NetworkSelection, PermissionSelection } from '../components'
import { handleError } from '@core/error/handlers'
import { Button, Spinner } from '@bloomwalletio/ui'
import { DrawerTemplate } from '@components'
import { IAccountState } from '@core/account'
import { DappConfigRoute } from '../dapp-config-route.enum'
import { closeDrawer } from '@desktop/auxiliary/drawer'
import { selectedAccount } from '@core/account/stores'
import { DappVerification } from '@auxiliary/wallet-connect/enums'
import { ISupportedNamespace, SupportedNamespaces } from '@auxiliary/wallet-connect/types'
import { time } from '@core/app/stores'
import { handleError } from '@core/error/handlers'
import { localize } from '@core/i18n'
import { getEvmNetworks } from '@core/network'
import { ALL_SUPPORTED_METHODS, SUPPORTED_EVENTS } from '@auxiliary/wallet-connect/constants'
import { activeAccounts } from '@core/profile/stores'
import { Router } from '@core/router'
import { MILLISECONDS_PER_SECOND } from '@core/utils'
import { closeDrawer } from '@desktop/auxiliary/drawer'
import { DappInfo } from '@ui'
import {
AccountSelection,
ConnectionSummary,
NetworkSelection,
PermissionSelection,
ConnectionRequestExpirationAlert,
} from '../components'
import { DappConfigRoute } from '../dapp-config-route.enum'
export let drawerRouter: Router<unknown>
Expand All @@ -37,6 +45,10 @@
? DappVerification.Scam
: ($sessionProposal?.verifyContext.verified.validation as DappVerification)
$: hasRequestExpired = $sessionProposal?.params.expiryTimestamp
? $sessionProposal.params.expiryTimestamp - $time.getTime() / MILLISECONDS_PER_SECOND <= 0
: false
let checkedAccounts: IAccountState[] = []
let checkedNetworks: string[] = []
let checkedMethods: string[] = []
Expand Down Expand Up @@ -107,7 +119,9 @@
}
function onCancelClick(): void {
rejectSession()
if (!hasRequestExpired) {
rejectSession()
}
closeDrawer()
}
Expand Down Expand Up @@ -136,7 +150,10 @@
{@const requiredNamespaces = $sessionProposal.params.requiredNamespaces}
{@const optionalNamespaces = $sessionProposal.params.optionalNamespaces}

<DappInfo metadata={$sessionProposal.params.proposer.metadata} {verifiedState} />
<div>
<DappInfo metadata={$sessionProposal.params.proposer.metadata} {verifiedState} />
<ConnectionRequestExpirationAlert expiryTimestamp={$sessionProposal.params.expiryTimestamp} />
</div>

<div class="px-6 flex-grow overflow-hidden">
{#if activeSelection === Selection.Summary}
Expand All @@ -146,9 +163,11 @@
editable
{supportedNamespaces}
onEditPermissionsClick={() =>
!loading ? (activeSelection = Selection.Permissions) : undefined}
onEditNetworksClick={() => (!loading ? (activeSelection = Selection.Networks) : undefined)}
onEditAccountsClick={() => (!loading ? (activeSelection = Selection.Accounts) : undefined)}
!loading || !hasRequestExpired ? (activeSelection = Selection.Permissions) : undefined}
onEditNetworksClick={() =>
!loading || !hasRequestExpired ? (activeSelection = Selection.Networks) : undefined}
onEditAccountsClick={() =>
!loading || !hasRequestExpired ? (activeSelection = Selection.Accounts) : undefined}
/>
</div>
{:else}
Expand Down Expand Up @@ -186,15 +205,17 @@
width="full"
on:click={onCancelClick}
disabled={loading}
text={localize('actions.reject')}
/>
<Button
width="full"
on:click={onConfirmClick}
disabled={loading}
busy={loading}
text={localize('actions.confirm')}
text={hasRequestExpired ? localize('actions.cancel') : localize('actions.reject')}
/>
{#if !hasRequestExpired}
<Button
width="full"
on:click={onConfirmClick}
disabled={loading}
busy={loading}
text={localize('actions.confirm')}
/>
{/if}
{:else}
<Button
variant="outlined"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { DrawerTemplate } from '@components'
import { sessionProposal } from '@auxiliary/wallet-connect/stores'
import { closeDrawer } from '@desktop/auxiliary/drawer'
import { SecurityWarning, UnsupportedDappHint } from '../components'
import { ConnectionRequestExpirationAlert, SecurityWarning, UnsupportedDappHint } from '../components'
import { getAllNetworkIds } from '@core/network'
import { ALL_SUPPORTED_METHODS } from '@auxiliary/wallet-connect/constants'
import { rejectSession } from '@auxiliary/wallet-connect/utils'
Expand All @@ -15,6 +15,8 @@
import { DappVerification, RpcMethod } from '@auxiliary/wallet-connect/enums'
import { ProposalTypes } from '@walletconnect/types'
import { Web3WalletTypes } from '@walletconnect/web3wallet'
import { time } from '@core/app/stores'
import { MILLISECONDS_PER_SECOND } from '@core/utils/constants'
export let drawerRouter: Router<unknown>
Expand Down Expand Up @@ -42,6 +44,10 @@
$: $sessionProposal && onSessionProposal($sessionProposal)
$: hasRequestExpired = $sessionProposal?.params.expiryTimestamp
? $sessionProposal.params.expiryTimestamp - $time.getTime() / MILLISECONDS_PER_SECOND <= 0
: false
function onSessionProposal(_sessionProposal: Web3WalletTypes.SessionProposal): void {
clearTimeout(timeout)
Expand Down Expand Up @@ -121,7 +127,10 @@
<div class="w-full h-full flex flex-col justify-between">
{#if $sessionProposal}
{@const metadata = $sessionProposal.params.proposer.metadata}
<DappInfo {metadata} {verifiedState} />
<div>
<DappInfo {metadata} {verifiedState} />
<ConnectionRequestExpirationAlert expiryTimestamp={$sessionProposal.params.expiryTimestamp} />
</div>

<div class="flex-grow overflow-hidden">
<div class="h-full overflow-scroll flex flex-col gap-5 p-6">
Expand Down Expand Up @@ -169,7 +178,7 @@
width="full"
variant="outlined"
on:click={onRejectClick}
text={localize(`actions.${fulfillsRequirements ? 'reject' : 'cancel'}`)}
text={localize(`actions.${fulfillsRequirements && !hasRequestExpired ? 'reject' : 'cancel'}`)}
/>
{#if fulfillsRequirements && verifiedState !== DappVerification.Scam}
<Button width="full" on:click={onContinueClick} text={localize('actions.continue')} />
Expand Down
6 changes: 3 additions & 3 deletions packages/shared/src/lib/core/utils/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const getBestTimeDuration = (millis: number, noDurationUnit: Duration = '
return zeroTime
}

export function getTimeDifference(lateDate: Date, earlyDate: Date): string {
export function getTimeDifference(lateDate: Date, earlyDate: Date, showSeconds: boolean = false): string {
const elapsedTime = lateDate.getTime() - earlyDate.getTime()
const years = Math.floor(elapsedTime / (MILLISECONDS_PER_SECOND * SECONDS_PER_DAY * DAYS_PER_YEAR))
const days = Math.floor(elapsedTime / (MILLISECONDS_PER_SECOND * SECONDS_PER_DAY)) % DAYS_PER_YEAR
Expand All @@ -89,9 +89,9 @@ export function getTimeDifference(lateDate: Date, earlyDate: Date): string {
} else if (hours > 0 && minutes > 0) {
return `${hours}h ${minutes}min`
} else if (minutes > 0) {
return `${minutes}min`
return showSeconds ? `${minutes}min ${seconds}s` : `${minutes}min`
} else if (seconds > 0) {
return '<1min'
return showSeconds ? `${seconds}s` : '<1min'
} else {
return ''
}
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,8 @@
},
"confirmConnection": {
"title": "Connect with an application",
"expired": "Connection request has expired",
"expiresIn": "Connection request expires in",
"permissions": {
"step": "Permissions",
"tip": "These are limited permissions for the dApp to send an interaction request for your approval. Only approve apps you know and trust.",
Expand Down

0 comments on commit 0b99994

Please sign in to comment.