Skip to main content
Version: 0.11.0

dApp Approval

When a dApp requests your accounts or asks you to sign a transaction, TezosX Wallet opens a dedicated approval window for your consent. No dApp action is taken until you explicitly approve.

When approvals are triggered

dApp callApproval type
eth_requestAccountsConnection request
eth_sendTransactionTransaction request
All other methodsPass-through (no approval needed)

Connection request

A site calling eth_requestAccounts is asking for permission to know your EVM address.

The approval window shows:

  • Origin — the requesting site's hostname (e.g. app.uniswap.org)
  • What it gets — your EVM alias (0x…); never your seed phrase or secret key
  • Approve / Reject buttons

If you approve, the wallet:

  1. Stores a StoredSession (origin, tz1, evmAlias, chainId, connectedAt) in chrome.storage.local
  2. Returns [evmAlias] to the dApp

If you reject, the dApp receives an EIP-1193 error 4001 — User rejected the request.

Transaction request

A site calling eth_sendTransaction is asking you to sign and broadcast a transaction.

The approval window shows two cards stacked vertically:

dApp intent — what the page asked for:

  • To — destination address as the dApp specified
  • Value — amount in wei
  • Data — raw hex calldata (if any)

What you actually sign (present only for Tezos-source accounts, since 0.11.0) — the resolved Michelson call your tz1 will commit to:

  • Michelson target — the NAC gateway KT1… your op targets
  • Entrypointdefault for bare value transfers, call_evm for ABI calls
  • Selector — the 4-byte function selector, present only when the entrypoint is call_evm. Resolved against a curated allow-list; unknown selectors are rejected by the relayer before the popup opens
  • Debit (mutez) — the actual mutez amount that will move from your tz1. Wei amounts not divisible by 10¹² (1 mutez) are rejected upstream; what you see here is exact

The two cards let you verify the dApp's stated intent matches what the kernel will actually execute. EVM-source accounts skip the second card — they sign the EVM tx directly with no cross-runtime translation.

  • Method — decoded method signature if resolvable (e.g. transfer(address,uint256))
  • Approve / Reject buttons

If you approve, the wallet signs the L1 operation via LocalSignerClient and returns the synthetic transaction hash to the dApp.

Session gating

Since 0.11.0, signature methods (eth_sendTransaction, personal_sign, eth_signTypedData_v4) require an active session for the calling origin — the page must have completed eth_requestAccounts first. Calls from unconnected tabs receive EIP-1193 error 4100 (unauthorised) directly, with no popup. This matches the standard EIP-1193 contract; the Connect step is no longer cosmetic.

Approval window lifecycle

The approval window is a separate Chrome popup (not the extension popup). It has its own URL (approve.html?requestId=…) and is closed automatically after the decision.

Toolbar badge — pending request counter

Since 0.6.0, the toolbar icon displays a badge with the count of pending approvals so you don't miss one if you switched tabs:

  • A new eth_requestAccounts or eth_sendTransaction triggers the badge to show 1 (or N if several queue up).
  • The badge is cleared as soon as you approve, reject, or close an approval window.
  • The badge is also cleared on lock and on service-worker restart, so a stale "1" can never outlive the actual queue.

Implementation lives in lib/badge.ts (setPendingBadge(count) / clearPendingBadge()); the colour (var(--tx-purple)#a78bfa) is centralised in BADGE_BG_COLOR so the badge stays visually consistent with the rest of the wallet design.

What if I close the window?

Closing the approval window with the Chrome × button is treated as an explicit reject. The wallet listens to chrome.windows.onRemoved and resolves the pending request with 4001 — User rejected the request, so the dApp's promise never hangs and the badge decrements correctly.

Pending requests on lock

Locking the wallet also rejects every pending approval (rejectAll()); each waiting dApp receives 4001 — User rejected the request.