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
| Method | Status | Description |
|---|---|---|
eth_requestAccounts | ✅ | Opens Temple via Beacon, returns ['0xAlias'] |
eth_accounts | ✅ | Returns current connected alias |
eth_chainId | ✅ | Returns Tezos X chain ID |
net_version | ✅ | Chain ID as decimal string |
eth_sendTransaction | ✅ | Routes via NAC gateway, returns synthetic hash |
eth_getBalance | ✅ | Balance of the 0x alias |
eth_getTransactionByHash | ✅ | Resolves real kernel tx; scans blocks from send-time snapshot |
eth_getTransactionReceipt | ✅ | Resolves real kernel receipt; synthetic fallback |
eth_getTransactionCount | ✅ | Proxied to Tezlink |
eth_call | ✅ | Proxied to Tezlink |
wallet_revokePermissions | ✅ | Disconnects Temple session |
| (any other method) | ✅ | Proxied to the Tezlink EVM node |
eth_sign | ❌ Not supported | Out of scope V1 |
personal_sign | ❌ Not supported | SIWE requires kernel ERC-1271 (0.3.0) |
eth_signTypedData | ❌ Not supported | EIP-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:
- Scans EVM blocks from the recorded send-time block up to the current head.
- Matches the first unclaimed transaction whose
fromortoequals the user's alias (the kernel may set either side to the alias depending on the call flavor). - 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 reallogs,gasUsed, andblockNumber.
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' }]
});