diff --git a/e2e/deposit-to-a-zone.test.ts b/e2e/deposit-to-a-zone.test.ts
index 56b2e73e..a57f5847 100644
--- a/e2e/deposit-to-a-zone.test.ts
+++ b/e2e/deposit-to-a-zone.test.ts
@@ -25,11 +25,8 @@ test('prepare zone access and deposit to Zone A', async ({ page }) => {
timeout: 30000,
})
- const authorizeButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone A reads$/i })
- .first()
+ const authorizeButton = page.getByRole('button', { name: 'Authorize Zone A reads' }).first()
await expect(authorizeButton).toBeVisible({ timeout: 30000 })
- await expect(authorizeButton).toBeEnabled({ timeout: 90000 })
await authorizeButton.click()
const getFundsButton = page.getByRole('button', { name: /^Get testnet pathUSD$/i }).first()
diff --git a/e2e/send-tokens-across-zones.test.ts b/e2e/send-tokens-across-zones.test.ts
index 5a88b4a2..7e1ea954 100644
--- a/e2e/send-tokens-across-zones.test.ts
+++ b/e2e/send-tokens-across-zones.test.ts
@@ -25,19 +25,14 @@ test('send pathUSD from Zone A into Zone B', async ({ page }) => {
timeout: 30000,
})
- const authorizeSourceButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone A reads$/i })
- .first()
+ const authorizeSourceButton = page.getByRole('button', { name: 'Authorize Zone A reads' }).first()
await expect(authorizeSourceButton).toBeVisible({ timeout: 30000 })
- await expect(authorizeSourceButton).toBeEnabled({ timeout: 90000 })
await authorizeSourceButton.click()
const getFundsButton = page.getByRole('button', { name: /^Get testnet pathUSD$/i }).first()
const topUpButton = page.getByRole('button', { name: /^Approve \+ top up Zone A$/i }).first()
const sendButton = page.getByRole('button', { name: /^Send 25 pathUSD into Zone B$/i }).first()
- const authorizeTargetButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone B reads$/i })
- .first()
+ const authorizeTargetButton = page.getByRole('button', { name: 'Authorize Zone B reads' }).first()
await expect
.poll(
@@ -66,7 +61,6 @@ test('send pathUSD from Zone A into Zone B', async ({ page }) => {
await sendButton.click()
await expect(authorizeTargetButton).toBeVisible({ timeout: 120000 })
- await expect(authorizeTargetButton).toBeEnabled({ timeout: 90000 })
await authorizeTargetButton.click()
await expect(
diff --git a/e2e/send-tokens-within-a-zone.test.ts b/e2e/send-tokens-within-a-zone.test.ts
index a8b9a743..f656dabe 100644
--- a/e2e/send-tokens-within-a-zone.test.ts
+++ b/e2e/send-tokens-within-a-zone.test.ts
@@ -25,11 +25,8 @@ test('prepare zone balance and send tokens within Zone A', async ({ page }) => {
timeout: 30000,
})
- const authorizeButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone A reads$/i })
- .first()
+ const authorizeButton = page.getByRole('button', { name: 'Authorize Zone A reads' }).first()
await expect(authorizeButton).toBeVisible({ timeout: 30000 })
- await expect(authorizeButton).toBeEnabled({ timeout: 90000 })
await authorizeButton.click()
const getFundsButton = page.getByRole('button', { name: /^Get testnet pathUSD$/i }).first()
diff --git a/e2e/swap-across-zones.test.ts b/e2e/swap-across-zones.test.ts
index 2cf3edcf..c6db47bb 100644
--- a/e2e/swap-across-zones.test.ts
+++ b/e2e/swap-across-zones.test.ts
@@ -25,11 +25,8 @@ test('swap pathUSD from Zone A into betaUSD on Zone B', async ({ page }) => {
timeout: 30000,
})
- const authorizeSourceButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone A reads$/i })
- .first()
+ const authorizeSourceButton = page.getByRole('button', { name: 'Authorize Zone A reads' }).first()
await expect(authorizeSourceButton).toBeVisible({ timeout: 30000 })
- await expect(authorizeSourceButton).toBeEnabled({ timeout: 90000 })
await authorizeSourceButton.click()
const getFundsButton = page.getByRole('button', { name: /^Get testnet pathUSD$/i }).first()
@@ -37,9 +34,7 @@ test('swap pathUSD from Zone A into betaUSD on Zone B', async ({ page }) => {
const swapButton = page
.getByRole('button', { name: /^Swap 25 pathUSD into Zone B betaUSD$/i })
.first()
- const authorizeTargetButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone B reads$/i })
- .first()
+ const authorizeTargetButton = page.getByRole('button', { name: 'Authorize Zone B reads' }).first()
await expect
.poll(
@@ -68,7 +63,6 @@ test('swap pathUSD from Zone A into betaUSD on Zone B', async ({ page }) => {
await swapButton.click()
await expect(authorizeTargetButton).toBeVisible({ timeout: 120000 })
- await expect(authorizeTargetButton).toBeEnabled({ timeout: 90000 })
await authorizeTargetButton.click()
await expect(
diff --git a/e2e/withdraw-from-a-zone.test.ts b/e2e/withdraw-from-a-zone.test.ts
index 3f07c303..38741e9e 100644
--- a/e2e/withdraw-from-a-zone.test.ts
+++ b/e2e/withdraw-from-a-zone.test.ts
@@ -27,11 +27,8 @@ test('prepare zone balance and withdraw from Zone A', async ({ page }) => {
timeout: 20000,
})
- const authorizeButton = page
- .getByRole('button', { name: /^Authoriz(?:e|ing) Zone A reads$/i })
- .first()
+ const authorizeButton = page.getByRole('button', { name: 'Authorize Zone A reads' }).first()
await expect(authorizeButton).toBeVisible({ timeout: 30000 })
- await expect(authorizeButton).toBeEnabled({ timeout: 90000 })
await authorizeButton.click()
const getFundsButton = page.getByRole('button', { name: /^Get testnet pathUSD$/i }).first()
diff --git a/src/components/guides/Demo.tsx b/src/components/guides/Demo.tsx
index 6c21f5ce..ceb60a3c 100644
--- a/src/components/guides/Demo.tsx
+++ b/src/components/guides/Demo.tsx
@@ -598,8 +598,6 @@ export function Button(
) {
const { className, disabled, render, size, static: static_, variant, ...rest } = props
const Element = render ? (p: typeof props) => React.cloneElement(render, p) : 'button'
- const accessibilityProps = render ? { 'aria-disabled': disabled || undefined } : { disabled }
-
return (
)
diff --git a/src/components/guides/zones/SendTokensAcrossZones.tsx b/src/components/guides/zones/SendTokensAcrossZones.tsx
index 7841ed48..89f13bf7 100644
--- a/src/components/guides/zones/SendTokensAcrossZones.tsx
+++ b/src/components/guides/zones/SendTokensAcrossZones.tsx
@@ -19,8 +19,7 @@ import {
} from '../../../lib/private-zones.ts'
import { useRootWebAuthnAccount } from '../../../lib/useRootWebAuthnAccount.ts'
import { useZoneAuthorization, type ZoneAuthClientLike } from '../../../lib/useZoneAuthorization.ts'
-import { Button, ExplorerLink, Logout, ReceiptHash, Step } from '../Demo'
-import { SignInButtons } from '../EmbedPasskeys'
+import { Button, ExplorerLink, Login, Logout, ReceiptHash, Step } from '../Demo'
import { pathUsd } from '../tokens'
import { useStickyStepCompletion } from './useStickyStepCompletion.ts'
@@ -78,7 +77,7 @@ export function SendTokensAcrossZones() {
: }
+ actions={connected ? : }
error={undefined}
number={1}
title="Create or use a passkey account on the public chain."
diff --git a/src/lib/useRootWebAuthnAccount.ts b/src/lib/useRootWebAuthnAccount.ts
index 16a36da6..2ca157d4 100644
--- a/src/lib/useRootWebAuthnAccount.ts
+++ b/src/lib/useRootWebAuthnAccount.ts
@@ -2,44 +2,26 @@
import { useQuery } from '@tanstack/react-query'
import { Account } from 'viem/tempo'
-import type { WebAuthnP256 } from 'viem/tempo'
import { useConnection } from 'wagmi'
-import { config, webAuthnRpId } from '../wagmi.config'
+import { config, webAuthnRpId } from '../wagmi.config.ts'
-type RootWebAuthnAccount = ReturnType
-type RootWebAuthnCredential = WebAuthnP256.P256Credential
-type RootWebAuthnAccountProvider = {
- getAccount: (options: {
- accessKey?: boolean | undefined
- address?: `0x${string}` | undefined
- signable?: boolean | undefined
- }) => RootWebAuthnAccount
- request: (args: { method: 'eth_accounts' }) => Promise
-}
+type RootWebAuthnCredential = Parameters[0]
export function useRootWebAuthnAccount() {
const { address, connector } = useConnection()
return useQuery({
- enabled: Boolean(address && connector?.id === 'webAuthn'),
- queryKey: ['root-webauthn-account', address],
+ enabled: Boolean(address && connector?.id === 'webAuthn' && webAuthnRpId),
+ queryKey: ['root-webauthn-account', address, webAuthnRpId],
queryFn: async () => {
- if (!address) throw new Error('account address not ready')
- if (!connector) throw new Error('connector not ready')
-
- const provider = await connector.getProvider()
- if (isRootWebAuthnAccountProvider(provider)) {
- await waitForProviderAccount(provider, address as `0x${string}`)
+ if (!webAuthnRpId) throw new Error('webauthn RP ID is not configured')
- return provider.getAccount({
- accessKey: false,
- address: address as `0x${string}`,
- signable: true,
- })
- }
+ const credential = await config.storage?.getItem('webAuthn.activeCredential')
+ if (!credential) throw new Error('webauthn credential not available')
- const credential = await waitForStoredCredential(address as `0x${string}`)
- return accountFromCredential(credential)
+ return Account.fromWebAuthnP256(credential as RootWebAuthnCredential, {
+ rpId: webAuthnRpId,
+ })
},
refetchOnReconnect: false,
refetchOnWindowFocus: false,
@@ -47,58 +29,3 @@ 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 5fd3bea1..b41d1e7f 100644
--- a/src/lib/useZoneAuthorization.ts
+++ b/src/lib/useZoneAuthorization.ts
@@ -4,8 +4,6 @@ import { useMutation, useQuery } from '@tanstack/react-query'
import type { Hex } from 'viem'
import { Storage as ZoneStorage } from 'viem/tempo'
-const zoneAuthorizationInfoTimeoutMs = 5_000
-
export type ZoneAuthClientLike = {
zone: {
getAuthorizationTokenInfo: () => Promise<{
@@ -46,10 +44,7 @@ export function useZoneAuthorization(parameters: {
if (accountToken) await storage.setItem(chainStorageKey, accountToken)
try {
- const info = await withTimeout(
- zoneClient.zone.getAuthorizationTokenInfo(),
- zoneAuthorizationInfoTimeoutMs,
- )
+ const info = await zoneClient.zone.getAuthorizationTokenInfo()
const expired = info.expiresAt <= BigInt(Math.floor(Date.now() / 1000))
const matchesAccount = info.account.toLowerCase() === lowerAddress
@@ -94,32 +89,17 @@ export function useZoneAuthorization(parameters: {
authorizeMutation,
error: authorizeMutation.error ?? statusQuery.error,
isAuthorized: statusQuery.data !== null && statusQuery.data !== undefined,
- isChecking: statusQuery.fetchStatus === 'fetching',
+ isChecking: statusQuery.isPending,
statusQuery,
}
}
-function withTimeout(promise: Promise, timeoutMs: number) {
- return Promise.race([
- promise,
- new Promise((_, reject) => {
- const timeout = setTimeout(() => {
- const error = new Error('zone authorization info request timed out')
- error.name = 'TimeoutError'
- reject(error)
- }, timeoutMs)
-
- promise.finally(() => clearTimeout(timeout))
- }),
- ])
-}
-
function isZoneAuthorizationError(error: unknown) {
const status = getErrorStatus(error)
if (status === 401 || status === 403) return true
const name = getErrorName(error)
- if (name === 'HttpRequestError' || name === 'TimeoutError') return true
+ if (name === 'HttpRequestError') return true
const message = getErrorMessage(error)
return /authorization token/i.test(message)
diff --git a/src/pages/protocol/zones/proving.mdx b/src/pages/protocol/zones/proving.mdx
index d20ac4e6..a63e39b4 100644
--- a/src/pages/protocol/zones/proving.mdx
+++ b/src/pages/protocol/zones/proving.mdx
@@ -3,8 +3,6 @@ title: Zone Proving
description: Batch submission and proof verification for Tempo zones, including the state transition function, ZK and TEE deployment modes, and ancestry proofs.
---
-import { StaticMermaidDiagram } from '../../../components/StaticMermaidDiagram'
-
# Zone Proving
:::info
@@ -73,22 +71,23 @@ pub fn prove_zone_batch(witness: BatchWitness) -> Result
### Execution Flow
- B["Verify Tempo state proofs"]
- B --> C["Initialize zone state from previous block hash"]
- C --> D{"Next zone block"}
- D --> E["Check parent hash and block number"]
- E --> F["Verify beneficiary is the sequencer"]
- F --> G["Execute advanceTempo system transaction if present"]
- G --> H["Execute user transactions via revm"]
- H --> I{"Final block in batch?"}
- I -- No --> J["Compute simplified zone block hash"]
+```mermaid
+flowchart TD
+ A[Batch witness] --> B[Verify Tempo state proofs]
+ B --> C[Initialize zone state from previous block hash]
+ C --> D{Next zone block}
+ D --> E[Check parent hash and block number]
+ E --> F[Verify beneficiary is the sequencer]
+ F --> G[Execute advanceTempo system transaction if present]
+ G --> H[Execute user transactions via revm]
+ H --> I{Final block in batch?}
+ I -- No --> J[Compute simplified zone block hash]
J --> D
- I -- Yes --> K["Execute finalizeWithdrawalBatch"]
- K --> L["Compute simplified zone block hash"]
- L --> M["Extract output commitments"]
- M --> N["Return batch output for verification"]
-`} />
+ I -- Yes --> K[Execute finalizeWithdrawalBatch]
+ K --> L[Compute simplified zone block hash]
+ L --> M[Extract output commitments]
+ M --> N[Return batch output for verification]
+```
1. **Verify Tempo state proofs.** Validate MPT proofs for all Tempo storage reads against Tempo state roots.
2. **Initialize zone state.** Load the zone state from the witness, binding the initial state root to the previous block hash.