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 bdd661db..2ca157d4 100644 --- a/src/lib/useRootWebAuthnAccount.ts +++ b/src/lib/useRootWebAuthnAccount.ts @@ -3,31 +3,24 @@ import { useQuery } from '@tanstack/react-query' import { Account } from 'viem/tempo' import { useConnection } from 'wagmi' +import { config, webAuthnRpId } from '../wagmi.config.ts' -type RootWebAuthnAccount = ReturnType -type RootWebAuthnAccountProvider = { - getAccount: (options: { - accessKey?: boolean | undefined - address?: `0x${string}` | undefined - signable?: boolean | undefined - }) => RootWebAuthnAccount -} +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') + if (!webAuthnRpId) throw new Error('webauthn RP ID is not configured') + + const credential = await config.storage?.getItem('webAuthn.activeCredential') + if (!credential) throw new Error('webauthn credential not available') - const provider = (await connector.getProvider()) as RootWebAuthnAccountProvider - return provider.getAccount({ - accessKey: false, - address: address as `0x${string}`, - signable: true, + return Account.fromWebAuthnP256(credential as RootWebAuthnCredential, { + rpId: webAuthnRpId, }) }, refetchOnReconnect: false, diff --git a/src/lib/useZoneAuthorization.ts b/src/lib/useZoneAuthorization.ts index e236c7d6..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 @@ -99,27 +94,12 @@ export function useZoneAuthorization(parameters: { } } -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.