Skip to main content
Version: 0.2.2

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
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; synthetic fallback
eth_getTransactionCountProxied to Tezlink
eth_callProxied to Tezlink
wallet_revokePermissionsDisconnects Temple session
(any other method)Proxied to the Tezlink EVM node
eth_sign❌ Not supportedOut of scope V1
personal_sign❌ Not supportedSIWE requires kernel ERC-1271 (0.3.0)
eth_signTypedData❌ Not supportedEIP-712 out of scope

Transaction receipts & the synthetic hash

When a dApp calls eth_sendTransaction, the relayer wraps the EVM transaction into a Tezos L1 operation targeting the NAC gateway's call_evm entrypoint. Temple then asks the user to sign the Tezos operation.

At this point the relayer only has the Tezos L1 operation hash — not the real EVM transaction hash. The EVM transaction is synthesized by the Tezos X kernel once the L1 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(l1_op_hash)) 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. Matches the first unclaimed transaction whose from or to equals the user's alias (the kernel may set either side to the alias depending on the call flavor).
  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.
  • Per-session claim set: once a real hash has been claimed by one pending op, no other pending op can match the same transaction.

Fallback

If no match is found within ~30 s (15 retries × 2 s), the relayer returns a synthetic receipt with status: 0x1 and empty logs so tx.wait() doesn't hang indefinitely.

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' }]
});