Skip to main content
Version: 0.7.0

EIP-1193 Provider

EIP-1193 defines the standard JavaScript interface for Ethereum providers — the window.ethereum API.

Interface

interface EIP1193Provider {
request(args: { method: string; params?: unknown[] }): Promise<unknown>;
on(event: string, listener: (...args: unknown[]) => void): void;
removeListener(event: string, listener: (...args: unknown[]) => void): void;
}

Implemented methods

MethodStatusDescription
eth_requestAccountsOpens Temple via Beacon, returns ['0xAlias']
eth_accountsReturns current connected alias
tez_getAccountsReturns the connected tz1 address (non-standard, Tezos X-specific)
eth_chainIdReturns Tezos X chain ID
net_versionChain ID as decimal string
eth_sendTransactionRoutes via NAC gateway, returns synthetic hash
eth_getBalanceBalance of the 0x alias
eth_getTransactionByHashResolves real kernel tx; scans blocks from send-time snapshot
eth_getTransactionReceiptResolves real kernel receipt; null while unresolved
eth_getTransactionCountProxied to Tezlink
eth_callProxied to Tezlink
eth_estimateGas / eth_gasPrice / eth_maxPriorityFeePerGas / eth_feeHistoryShort-circuited to fixed constants — see Fee model
wallet_revokePermissions / wallet_disconnectDisconnects the Temple session
(any other method)Proxied to the Tezlink EVM node
eth_sign❌ Rejected 4200Message signing is not supported
personal_sign❌ Rejected 4200Message signing is not supported
eth_signTypedData / _v3 / _v4❌ Rejected 4200EIP-712 signing is not supported

The five signing methods (eth_sign, personal_sign, eth_signTypedData, eth_signTypedData_v3, eth_signTypedData_v4) are rejected with EIP-1193 error code 4200 (unsupported method). There is no ECDSA key behind the 0x alias — it is a kernel-computed mapping of a tz1 account — so EVM-style message signatures cannot be produced by this provider.

Transaction receipts & the synthetic hash

When a dApp calls eth_sendTransaction, the relayer wraps the EVM transaction into a Michelson runtime operation targeting the NAC gateway (entrypoint call_evm, or call for a bare transfer). Temple then asks the user to sign the Tezos operation.

At this point the relayer only has the Michelson runtime operation hash — not the real EVM transaction hash. The EVM transaction is synthesized by the Tezos X kernel once the Michelson operation is included in a block, and its hash is computed as keccak256("CRAC-TX" || block_number_be || crac_id) where crac_id depends on how many cross-runtime calls appear in the same block. Therefore the real hash cannot be predicted at signing time.

Workaround: the relayer returns a synthetic hash (keccak256(michelson_op_hash), see l1OpHashToEvmHash) to the dApp right after signing, and records the EVM head block number at that moment. When the dApp later calls eth_getTransactionByHash(syntheticHash) or eth_getTransactionReceipt(syntheticHash), the resolver:

  1. Scans EVM blocks from the recorded send-time block up to the current head.
  2. Picks the matching kernel-synthesized transaction. Candidates whose from is the user's alias are preferred, with an exact to/value mirror of the original request winning over a from-only match (contract calls routed through the gateway carry the real call in the receipt logs, not the top-level fields). If no sender-side candidate exists, transactions to the alias are considered, but only when their receipt carries a log emitted by the NAC precompile — this covers kernel bookkeeping shapes such as the AliasForwarder.
  3. Caches the real hash on the pending op and proxies the original RPC call (eth_getTransactionByHash / eth_getTransactionReceipt) to Tezlink with the real hash, returning the real transaction and receipt — with real logs, gasUsed, and blockNumber.

Deduplication

Two invariants keep the resolver sane under the polling load ethers.js / viem put on providers:

  • Per-hash in-flight promise: concurrent calls for the same synthetic hash share the same block-scan promise instead of each starting a fresh scan.
  • Claim set: once a real hash has been claimed by one pending op, no other pending op can match the same transaction. When a PendingOpsStore is injected (as the wallet does), pending ops and claimed hashes are persisted so resolution state survives across provider instances.

Fallback

Each resolution attempt scans for ~30 s (15 retries × 2 s). While the real transaction has not been found:

  • eth_getTransactionByHash returns a pending-shaped transaction object (blockNumber: null), as EIP-1474 prescribes for a submitted-but-unmined transaction — so ethers.js / viem pollers keep polling instead of aborting.
  • eth_getTransactionReceipt returns null, the standard answer for a transaction that is not yet mined.
  • resolveSyntheticHash() (the public wallet-facing method) resolves to null on timeout, letting the caller fall back to the Michelson operation hash.

Example

// Connect
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
console.log(accounts); // ['0x341af4de...']

// Get chain
const chainId = await window.ethereum.request({ method: 'eth_chainId' });

// Send transaction
const hash = await window.ethereum.request({
method: 'eth_sendTransaction',
params: [{ to: '0x...', value: '0xde0b6b3a7640000' }]
});