From 5e5ede6dfbdca84a2feb057dbe7842b5da85311f Mon Sep 17 00:00:00 2001 From: Zygimantas <5236121+Zygimantass@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:26:53 +0200 Subject: [PATCH 1/3] fix(zones): zone auth key --- src/lib/useRootWebAuthnAccount.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/useRootWebAuthnAccount.ts b/src/lib/useRootWebAuthnAccount.ts index bdd661db..228bd3ab 100644 --- a/src/lib/useRootWebAuthnAccount.ts +++ b/src/lib/useRootWebAuthnAccount.ts @@ -1,7 +1,7 @@ 'use client' import { useQuery } from '@tanstack/react-query' -import { Account } from 'viem/tempo' +import type { Account } from 'viem/tempo' import { useConnection } from 'wagmi' type RootWebAuthnAccount = ReturnType From 7a9eed3d640e7cb973cb541bf1c80a0f9b2fe336 Mon Sep 17 00:00:00 2001 From: Zygimantas <5236121+Zygimantass@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:38:35 +0200 Subject: [PATCH 2/3] fix(zones): fix zone auth --- src/lib/useRootWebAuthnAccount.ts | 79 ++++++++++++++++++++++++++++--- src/lib/useZoneAuthorization.ts | 2 +- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/lib/useRootWebAuthnAccount.ts b/src/lib/useRootWebAuthnAccount.ts index 228bd3ab..7f730282 100644 --- a/src/lib/useRootWebAuthnAccount.ts +++ b/src/lib/useRootWebAuthnAccount.ts @@ -1,8 +1,10 @@ 'use client' import { useQuery } from '@tanstack/react-query' -import type { Account } from 'viem/tempo' +import { Account } from 'viem/tempo' +import type { P256Credential as RootWebAuthnCredential } from 'viem/tempo/WebAuthnP256' import { useConnection } from 'wagmi' +import { config, webAuthnRpId } from '../wagmi.config' type RootWebAuthnAccount = ReturnType type RootWebAuthnAccountProvider = { @@ -11,6 +13,7 @@ type RootWebAuthnAccountProvider = { address?: `0x${string}` | undefined signable?: boolean | undefined }) => RootWebAuthnAccount + request: (args: { method: 'eth_accounts' }) => Promise } export function useRootWebAuthnAccount() { @@ -23,12 +26,19 @@ export function useRootWebAuthnAccount() { if (!address) throw new Error('account address not ready') if (!connector) throw new Error('connector not ready') - const provider = (await connector.getProvider()) as RootWebAuthnAccountProvider - return provider.getAccount({ - accessKey: false, - address: address as `0x${string}`, - signable: true, - }) + const provider = await connector.getProvider() + if (isRootWebAuthnAccountProvider(provider)) { + await waitForProviderAccount(provider, address as `0x${string}`) + + return provider.getAccount({ + accessKey: false, + address: address as `0x${string}`, + signable: true, + }) + } + + const credential = await waitForStoredCredential(address as `0x${string}`) + return accountFromCredential(credential) }, refetchOnReconnect: false, refetchOnWindowFocus: false, @@ -36,3 +46,58 @@ export function useRootWebAuthnAccount() { staleTime: Number.POSITIVE_INFINITY, }) } + +function accountFromCredential(credential: RootWebAuthnCredential) { + return Account.fromWebAuthnP256(credential, webAuthnRpId ? { rpId: webAuthnRpId } : undefined) +} + +function isRootWebAuthnAccountProvider(value: unknown): value is RootWebAuthnAccountProvider { + return Boolean( + value && + typeof value === 'object' && + 'getAccount' in value && + typeof value.getAccount === 'function' && + 'request' in value && + typeof value.request === 'function', + ) +} + +async function waitForProviderAccount( + provider: RootWebAuthnAccountProvider, + address: `0x${string}`, + timeoutMs = 5_000, +) { + const deadline = Date.now() + timeoutMs + const normalizedAddress = address.toLowerCase() + + while (Date.now() < deadline) { + const accounts = await provider.request({ method: 'eth_accounts' }) + if (accounts.some((account) => account.toLowerCase() === normalizedAddress)) return + + await new Promise((resolve) => setTimeout(resolve, 100)) + } + + throw new Error(`webauthn account ${address} not ready`) +} + +async function waitForStoredCredential( + address: `0x${string}`, + timeoutMs = 5_000, +): Promise { + const deadline = Date.now() + timeoutMs + const normalizedAddress = address.toLowerCase() + + while (Date.now() < deadline) { + const credential = await config.storage?.getItem('webAuthn.activeCredential') + if (credential) { + const account = accountFromCredential(credential as RootWebAuthnCredential) + if (account.address.toLowerCase() === normalizedAddress) { + return credential as RootWebAuthnCredential + } + } + + await new Promise((resolve) => setTimeout(resolve, 100)) + } + + throw new Error(`webauthn credential for ${address} not ready`) +} diff --git a/src/lib/useZoneAuthorization.ts b/src/lib/useZoneAuthorization.ts index e236c7d6..5fd3bea1 100644 --- a/src/lib/useZoneAuthorization.ts +++ b/src/lib/useZoneAuthorization.ts @@ -94,7 +94,7 @@ export function useZoneAuthorization(parameters: { authorizeMutation, error: authorizeMutation.error ?? statusQuery.error, isAuthorized: statusQuery.data !== null && statusQuery.data !== undefined, - isChecking: statusQuery.isPending, + isChecking: statusQuery.fetchStatus === 'fetching', statusQuery, } } From f989ecfb8b3e1816ca4608d44383d092166fa59a Mon Sep 17 00:00:00 2001 From: Zygimantas <5236121+Zygimantass@users.noreply.github.com> Date: Thu, 16 Apr 2026 14:39:44 +0200 Subject: [PATCH 3/3] fix: build --- src/lib/useRootWebAuthnAccount.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib/useRootWebAuthnAccount.ts b/src/lib/useRootWebAuthnAccount.ts index 7f730282..16a36da6 100644 --- a/src/lib/useRootWebAuthnAccount.ts +++ b/src/lib/useRootWebAuthnAccount.ts @@ -2,11 +2,12 @@ import { useQuery } from '@tanstack/react-query' import { Account } from 'viem/tempo' -import type { P256Credential as RootWebAuthnCredential } from 'viem/tempo/WebAuthnP256' +import type { WebAuthnP256 } from 'viem/tempo' import { useConnection } from 'wagmi' import { config, webAuthnRpId } from '../wagmi.config' type RootWebAuthnAccount = ReturnType +type RootWebAuthnCredential = WebAuthnP256.P256Credential type RootWebAuthnAccountProvider = { getAccount: (options: { accessKey?: boolean | undefined