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

feat: support one click dapp connection and sign in #2543

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f855141
generalize proposal store
MarkNerdi May 31, 2024
68632a7
refactor selections
MarkNerdi May 31, 2024
ca51ba1
update connectionrequest view
MarkNerdi May 31, 2024
8bede4d
implement one click auth flow
MarkNerdi May 31, 2024
640d865
move approval function into own file
MarkNerdi May 31, 2024
f705d62
fix edit drawers
MarkNerdi May 31, 2024
109aac8
cleanup
MarkNerdi May 31, 2024
463f298
update connected dapps type
MarkNerdi May 31, 2024
7cf778b
update ui components
MarkNerdi May 31, 2024
e2a16b0
pr review comments
nicole-obrien May 31, 2024
1d7c451
Merge commit '9791497a5f1e6346a1fbfedb120c94518650ffac' into 2476----…
MarkNerdi Jun 17, 2024
af90d25
Merge commit '0b9999445fae257ef1101eaf4a333a6817d0b0d9' into 2476----…
MarkNerdi Jun 20, 2024
7c91d6a
Merge conflicts
MarkNerdi Jun 20, 2024
e03f70b
fix
MarkNerdi Jun 20, 2024
94fcdd1
Merge commit '9b02b6707fa57cb2f35d002ec9951edb05b9c512' into 2476----…
MarkNerdi Jun 23, 2024
8101eb9
fixes
MarkNerdi Jun 23, 2024
203132b
Merge commit '4b234629495205742a87b3810824a577b4d36a1c' into 2476----…
MarkNerdi Jun 25, 2024
c18df81
merge fixes
MarkNerdi Jun 25, 2024
a6be463
merge fixes
MarkNerdi Jun 25, 2024
625b2cd
create shared connection flow component
MarkNerdi Jun 25, 2024
86ccc8e
use shared connection comp for one click auth
MarkNerdi Jun 25, 2024
3bb90c3
fix locale
MarkNerdi Jun 25, 2024
49f1882
fix types
MarkNerdi Jun 25, 2024
f3ccc00
fix authenticate approval
MarkNerdi Jun 25, 2024
14842f1
cleanup session
MarkNerdi Jun 25, 2024
da99aae
show different description
MarkNerdi Jun 26, 2024
00f4466
pr review comments
nicole-obrien Jun 26, 2024
9f446af
type issues
nicole-obrien Jun 26, 2024
152df42
Merge branch 'develop' into 2476----support-one-click-dapp-connection…
nicole-obrien Jun 26, 2024
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
2 changes: 1 addition & 1 deletion packages/desktop/components/menus/DappActionsMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
]

$: dappName = dapp.metadata?.name ?? localize('general.unknown')
$: hasActiveSession = !!dapp.session
$: hasActiveSession = !!dapp.sessionTopic

function onRemoveClick(): void {
openPopup({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
export let onClick: (() => unknown) | undefined = undefined

$: networkIds = Object.values(
dapp.session?.namespaces ?? getPersistedDappNamespacesForDapp(dapp.metadata?.url ?? '')?.supported ?? {}
dapp.namespaces ?? getPersistedDappNamespacesForDapp(dapp.metadata?.url ?? '')?.supported ?? {}
).flatMap((namespace) => namespace.chains as NetworkId[])

$: verifiedState = $activeProfileId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,35 +8,115 @@
selectedDapp,
sessionInitiationRequest,
getPersistedDapp,
SessionInitiationRequest,
} from '@auxiliary/wallet-connect/stores'
import { onMount } from 'svelte'
import { buildSupportedNamespacesFromSelections } from '@auxiliary/wallet-connect/actions'
import { updateSession } from '@auxiliary/wallet-connect/utils'
import { IDappMetadata, ISelections } from '@auxiliary/wallet-connect/interface'
import { getNetworksAndMethodsFromNamespaces, updateSession } from '@auxiliary/wallet-connect/utils'
import { IConnectedDapp, IDappMetadata, ISelections } from '@auxiliary/wallet-connect/interface'
import { DappInfo } from '@ui'
import { ALL_EVM_METHODS } from '@auxiliary/wallet-connect/constants'

export let drawerRouter: Router<unknown>
export let selections: ISelections
export let titleLocale: string
export let disableContinue: boolean

$: dappMetadata = $selectedDapp?.metadata ?? ($sessionInitiationRequest?.params.proposer.metadata as IDappMetadata)
const dappMetadata = getDappMetadata($selectedDapp, $sessionInitiationRequest)
const { requiredMethods, optionalMethods } = getMethodsForNamespaces($selectedDapp, $sessionInitiationRequest)
const { requiredNetworks, optionalNetworks } = getNetworksForNamespaces($selectedDapp, $sessionInitiationRequest)

$: persistedDapp = dappMetadata ? getPersistedDapp(dappMetadata.url) : undefined
$: requiredNamespaces =
$selectedDapp?.session?.requiredNamespaces ?? $sessionInitiationRequest?.params.requiredNamespaces ?? {}
$: optionalNamespaces =
$selectedDapp?.session?.optionalNamespaces ?? $sessionInitiationRequest?.params.optionalNamespaces ?? {}

function getDappMetadata(
selectedDapp: IConnectedDapp | undefined,
sessionInitiationRequest: SessionInitiationRequest | undefined
): IDappMetadata | undefined {
if (selectedDapp) {
return selectedDapp?.metadata
} else if (sessionInitiationRequest?.type === 'session_proposal') {
return sessionInitiationRequest?.payload.params.proposer.metadata as IDappMetadata
} else if (sessionInitiationRequest?.type === 'session_authenticate') {
return sessionInitiationRequest?.payload.params.requester.metadata as IDappMetadata
} else {
return undefined
}
}

function getMethodsForNamespaces(
selectedDapp: IConnectedDapp | undefined,
sessionInitiationRequest: SessionInitiationRequest | undefined
): { requiredMethods: string[]; optionalMethods: string[] } {
if (selectedDapp) {
const { requiredNamespaces, optionalNamespaces } = selectedDapp ?? {}

const { requiredMethods, optionalMethods } = getNetworksAndMethodsFromNamespaces(
requiredNamespaces ?? {},
optionalNamespaces ?? {}
)
return { requiredMethods, optionalMethods }
} else if (sessionInitiationRequest?.type === 'session_proposal') {
const { requiredNamespaces, optionalNamespaces } = sessionInitiationRequest.payload?.params ?? {}
const { requiredMethods, optionalMethods } = getNetworksAndMethodsFromNamespaces(
requiredNamespaces ?? {},
optionalNamespaces ?? {}
)
return { requiredMethods, optionalMethods }
} else if (sessionInitiationRequest?.type === 'session_authenticate') {
return { requiredMethods: [], optionalMethods: ALL_EVM_METHODS }
} else {
return { requiredMethods: [], optionalMethods: [] }
}
}

function getNetworksForNamespaces(
selectedDapp: IConnectedDapp | undefined,
sessionInitiationRequest: SessionInitiationRequest | undefined
): { requiredNetworks: string[]; optionalNetworks: string[] } {
if (selectedDapp) {
const { requiredNamespaces, optionalNamespaces } = selectedDapp ?? {}
const { requiredNetworks, optionalNetworks } = getNetworksAndMethodsFromNamespaces(
requiredNamespaces ?? {},
optionalNamespaces ?? {}
)
return { requiredNetworks, optionalNetworks }
} else if (sessionInitiationRequest?.type === 'session_proposal') {
const { requiredNamespaces, optionalNamespaces } = sessionInitiationRequest.payload?.params ?? {}
const { requiredNetworks, optionalNetworks } = getNetworksAndMethodsFromNamespaces(
requiredNamespaces ?? {},
optionalNamespaces ?? {}
)
return { requiredNetworks, optionalNetworks }
} else if (sessionInitiationRequest?.type === 'session_authenticate') {
// TODO: Implement this
return { requiredNetworks: [], optionalNetworks: [] }
} else {
return { requiredNetworks: [], optionalNetworks: [] }
}
}

function onConfirmClick(): void {
// TODO: Implement this
if ($sessionInitiationRequest?.type === 'session_authenticate') {
return
}

const requiredNamespaces =
$selectedDapp?.requiredNamespaces ?? $sessionInitiationRequest?.payload?.params.requiredNamespaces ?? {}
const optionalNamespaces =
$selectedDapp?.optionalNamespaces ?? $sessionInitiationRequest?.payload?.params.optionalNamespaces ?? {}

const updatedNamespace = buildSupportedNamespacesFromSelections(
selections,
requiredNamespaces,
optionalNamespaces,
persistedDapp?.namespaces.supported
)
updateSupportedDappNamespacesForDapp(dappMetadata.url, updatedNamespace)
if ($selectedDapp?.session) {
updateSession($selectedDapp.session.topic, updatedNamespace)
if (dappMetadata) {
updateSupportedDappNamespacesForDapp(dappMetadata.url, updatedNamespace)
}
if ($selectedDapp?.sessionTopic) {
updateSession($selectedDapp.sessionTopic, updatedNamespace)
}
drawerRouter.previous()
}
Expand All @@ -60,8 +140,10 @@
<div class="h-full flex flex-col gap-8 overflow-scroll">
<slot
persistedSupportedNamespaces={persistedDapp?.namespaces.supported}
{requiredNamespaces}
{optionalNamespaces}
{requiredMethods}
{optionalMethods}
{requiredNetworks}
{optionalNetworks}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import { ProposalTypes } from '@walletconnect/types'
import { getAllNetworkIds } from '@core/network/utils'
import { onMount } from 'svelte'
import { Selection } from '@ui'
Expand All @@ -9,43 +8,41 @@
import { SelectionOption } from '@core/utils/interfaces'

export let checkedNetworks: string[]
export let requiredNamespaces: ProposalTypes.RequiredNamespaces
export let optionalNamespaces: ProposalTypes.RequiredNamespaces
export let requiredNetworks: string[]
export let optionalNetworks: string[]
export let supportedNamespaces: SupportedNamespaces | undefined = undefined

const localeKey = 'views.dashboard.drawers.dapps.confirmConnection.networks'

let requiredNetworks: SelectionOption<NetworkId>[] = []
let optionalNetworks: SelectionOption<NetworkId>[] = []
let requiredNetworksOptions: SelectionOption<NetworkId>[] = []
let optionalNetworksOptions: SelectionOption<NetworkId>[] = []
function setNetworkSelections(): void {
const networks: Record<string, SelectionOption<NetworkId>> = {}
for (const namespace of Object.values(requiredNamespaces)) {
for (const chainId of namespace.chains ?? []) {
const chainName = getEvmNetwork(chainId as NetworkId)?.name ?? chainId
networks[chainId] = { label: chainName, value: chainId as NetworkId, checked: true, required: true }
}
for (const chainId of requiredNetworks) {
const chainName = getEvmNetwork(chainId as NetworkId)?.name ?? chainId
networks[chainId] = { label: chainName, value: chainId as NetworkId, checked: true, required: true }
}
const supportedNetworks = getAllNetworkIds()
for (const [namespaceId, namespace] of Object.entries(optionalNamespaces)) {
const persistedNamespace = supportedNamespaces?.[namespaceId]
for (const chainId of namespace.chains ?? []) {
if (!networks[chainId] && supportedNetworks.includes(chainId)) {
const isChecked = persistedNamespace?.chains?.includes(chainId) ?? true
const chainName = getEvmNetwork(chainId as NetworkId)?.name ?? chainId
networks[chainId] = {
label: chainName,
value: chainId as NetworkId,
checked: isChecked,
required: false,
}

const persistedChains = Object.values(supportedNamespaces ?? {}).flatMap(({ chains }) => chains)
for (const chainId of optionalNetworks) {
if (!networks[chainId] && supportedNetworks.includes(chainId)) {
const isChecked = persistedChains?.includes(chainId) ?? true
const chainName = getEvmNetwork(chainId as NetworkId)?.name ?? chainId
networks[chainId] = {
label: chainName,
value: chainId as NetworkId,
checked: isChecked,
required: false,
}
}
}
requiredNetworks = Object.values(networks).filter((network) => network.required)
optionalNetworks = Object.values(networks).filter((network) => !network.required)

requiredNetworksOptions = Object.values(networks).filter((network) => network.required)
optionalNetworksOptions = Object.values(networks).filter((network) => !network.required)
}

$: checkedNetworks = [...requiredNetworks, ...optionalNetworks]
$: checkedNetworks = [...requiredNetworksOptions, ...optionalNetworksOptions]
.filter((selection) => selection.checked)
.map((selection) => selection.value)

Expand All @@ -55,16 +52,16 @@
</script>

<div class="h-full flex flex-col gap-8">
{#if requiredNetworks.length}
{#if requiredNetworksOptions.length}
<Selection
bind:selectionOptions={requiredNetworks}
bind:selectionOptions={requiredNetworksOptions}
disableSelectAll
title={localize(`${localeKey}.requiredTitle`)}
/>
{/if}
{#if optionalNetworks.length}
{#if optionalNetworksOptions.length}
<Selection
bind:selectionOptions={optionalNetworks}
bind:selectionOptions={optionalNetworksOptions}
title={localize(`${localeKey}.optionalTitle`)}
error={checkedNetworks.length ? undefined : localize(`${localeKey}.empty`)}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<script lang="ts">
import { ProposalTypes } from '@walletconnect/types'
import { METHODS_FOR_PERMISSION } from '@auxiliary/wallet-connect/constants'
import { onMount } from 'svelte'
import { Selection } from '@ui'
Expand All @@ -11,25 +10,21 @@
import { SelectionOption } from '@core/utils/interfaces'

export let checkedMethods: string[]
export let requiredNamespaces: ProposalTypes.RequiredNamespaces
export let optionalNamespaces: ProposalTypes.RequiredNamespaces
export let requiredMethods: string[]
export let optionalMethods: string[]
export let supportedNamespaces: SupportedNamespaces | undefined = undefined

const localeKey = 'views.dashboard.drawers.dapps.confirmConnection.permissions'
let requiredPermissions: SelectionOption<string>[] = []
let optionalPermissions: SelectionOption<string>[] = []
let requiredPermissionsOptions: SelectionOption<string>[] = []
let optionalPermissionsOptions: SelectionOption<string>[] = []

function setPermissionSelections(): void {
const checkedMethods: { [method: string]: boolean } = {}
const addedPermission: { [permission: string]: boolean } = {}

const methods = [
...Object.values(requiredNamespaces).flatMap((namespace) =>
namespace.methods.map((method) => ({ method, required: true }))
),
...Object.values(optionalNamespaces).flatMap((namespace) =>
namespace.methods.map((method) => ({ method, required: false }))
),
...requiredMethods.map((method) => ({ method, required: true })),
...optionalMethods.map((method) => ({ method, required: false })),
]

for (const method of methods) {
Expand All @@ -55,17 +50,17 @@
required: method.required,
}
if (method.required) {
requiredPermissions = [...requiredPermissions, option]
requiredPermissionsOptions = [...requiredPermissionsOptions, option]
} else {
optionalPermissions = [...optionalPermissions, option]
optionalPermissionsOptions = [...optionalPermissionsOptions, option]
}
}
}

$: requiredPermissions, optionalPermissions, (checkedMethods = getMethodsFromCheckedPermissions())
$: requiredPermissionsOptions, optionalPermissionsOptions, (checkedMethods = getMethodsFromCheckedPermissions())

function getMethodsFromCheckedPermissions(): string[] {
return [...requiredPermissions, ...optionalPermissions]
return [...requiredPermissionsOptions, ...optionalPermissionsOptions]
.filter((selection) => selection.checked)
.flatMap((selection) => METHODS_FOR_PERMISSION[selection.value])
}
Expand All @@ -75,26 +70,26 @@
})
</script>

{#if requiredPermissions.length || optionalPermissions.length}
{#if requiredPermissionsOptions.length || optionalPermissionsOptions.length}
<div class="h-full flex flex-col gap-8">
{#if requiredPermissions.length}
{#if requiredPermissionsOptions.length}
<Selection
bind:selectionOptions={requiredPermissions}
bind:selectionOptions={requiredPermissionsOptions}
disableSelectAll
title={localize(`${localeKey}.requiredTitle`)}
/>
{/if}
{#if optionalPermissions.length}
{#if optionalPermissionsOptions.length}
<Selection
bind:selectionOptions={optionalPermissions}
bind:selectionOptions={optionalPermissionsOptions}
title={localize(`${localeKey}.optionalTitle`)}
error={checkedMethods.length ? undefined : localize(`${localeKey}.empty`)}
/>
{/if}
</div>
{:else}
<selection-component class="h-full flex flex-col gap-4">
<Text textColor="secondary">{localize(`${localeKey}.title`)}</Text>
<Text textColor="secondary">{localize(`${localeKey}.step`)}</Text>

<div class="w-full flex-grow flex justify-center items-center">
<Text type="body2">{localize(`${localeKey}.noPermissionsRequired`)}</Text>
Expand Down
Loading
Loading