You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/specs/zone_spec.md
+34-19Lines changed: 34 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -193,20 +193,22 @@ The portal gives the messenger max approval for each enabled token so that withd
193
193
194
194
### Zone Predeploys
195
195
196
-
Each zone has four system contracts deployed at genesis at fixed addresses:
196
+
Each zone has six system contracts deployed at genesis at fixed addresses:
197
197
198
198
| Predeploy | Address | Purpose |
199
199
|-----------|---------|---------|
200
200
|[`TempoState`](#itempostate)|`0x1c00...0000`| Stores finalized Tempo block headers and provides storage read access to Tempo contracts. |
201
201
|[`ZoneInbox`](#izoneinbox)|`0x1c00...0001`| Advances the zone's view of Tempo and processes incoming deposits. Sole mint authority. |
202
202
|[`ZoneOutbox`](#izoneoutbox)|`0x1c00...0002`| Handles withdrawal requests and batch finalization. Sole burn authority. |
203
203
|[`ZoneConfig`](#izoneconfig)|`0x1c00...0003`| Central configuration. Reads the sequencer address and token registry from Tempo via `TempoState`. |
204
+
|`TempoStateReader`|`0x1c00...0004`| Precompile stub for reading Tempo L1 storage. Actual reads are performed by the zone node and validated against the `tempoStateRoot`. |
205
+
|`ZoneTxContext`|`0x1c00...0005`| Provides the current transaction hash to system contracts (used by `ZoneOutbox` for `senderTag` computation). |
204
206
205
207
`ZoneConfig` reads the sequencer address and token registry from the portal on Tempo via `TempoState` storage reads, making Tempo the single source of truth for zone configuration. See [Tempo State Reads](#tempo-state-reads) for details.
206
208
207
209
### Zone Token Model
208
210
209
-
Zones have no TIP-20 factory and contract creation is disabled (`CREATE` and `CREATE2` revert). All TIP-20 tokens on a zone are representations of Tempo tokens, deployed at the same address as on Tempo. When the sequencer enables a token on the portal, the zone node provisions a TIP-20 precompile at that address.
211
+
Contract creation is disabled on zones (`CREATE` and `CREATE2` revert). All TIP-20 tokens on a zone are representations of Tempo tokens, deployed at the same address as on Tempo. When the sequencer enables a token on the portal, the zone's TIP-20 factory precompile (at `0x20Fc000000000000000000000000000000000000`) provisions a TIP-20 token precompile at that address. The factory is called by `ZoneInbox` during `advanceTempo` and is not user-accessible.
210
212
211
213
Token supply on the zone is controlled exclusively by the system contracts:
212
214
@@ -236,7 +238,7 @@ The sequencer configures two gas rates that determine fees for deposits and with
Both rates are denominated in token units per gas unit. A single uniform `zoneGasRate` applies to all tokens. Fees are paid in the same token being deposited or withdrawn.
242
244
@@ -419,14 +421,15 @@ sequenceDiagram
419
421
The withdrawal fee compensates the sequencer for Tempo-side gas costs:
The user specifies `gasLimit` covering all execution costs on Tempo (processing overhead plus any callback). The fee is paid in the same token being withdrawn. On success, `amount` goes to the recipient and `fee` goes to the sequencer. On failure (bounce-back), only `amount` is re-deposited to `fallbackRecipient`; the sequencer keeps the fee.
428
+
`WITHDRAWAL_BASE_GAS` (50,000) covers the fixed overhead of processing a withdrawal on Tempo (queue dequeue, transfer, event emission). The user specifies `gasLimit` covering any additional execution costs (e.g., callback gas). For simple withdrawals with no callback, use `gasLimit = 0`. The fee is paid in the same token being withdrawn. On success, `amount` goes to the recipient and `fee` goes to the sequencer. On failure (bounce-back), only `amount` is re-deposited to `fallbackRecipient`; the sequencer keeps the fee.
426
429
427
430
### Withdrawal Batching
428
431
429
-
At the end of the final block in a batch, the sequencer calls `finalizeWithdrawalBatch(count)` on the `ZoneOutbox`. This constructs a hash chain from pending withdrawals in LIFO order (newest to oldest), so the oldest withdrawal ends up outermost, enabling FIFO processing on Tempo:
432
+
At the end of the final block in a batch, the sequencer calls `finalizeWithdrawalBatch(count, blockNumber, encryptedSenders)` on the `ZoneOutbox`. The `blockNumber` must match the current zone block number. The `encryptedSenders` array carries one ciphertext per finalized withdrawal for [authenticated withdrawals](#authenticated-withdrawals) (empty bytes for withdrawals without `revealTo`). This constructs a hash chain from pending withdrawals in LIFO order (newest to oldest), so the oldest withdrawal ends up outermost, enabling FIFO processing on Tempo:
The `txHash` is the hash of the `requestWithdrawal` transaction on the zone. Since zone transaction data is not published, `txHash` acts as a blinding factor known only to the sender and the sequencer.
489
492
490
-
The sender can optionally specify a `revealTo` public key (compressed secp256k1, 33 bytes) when requesting the withdrawal. If provided, the sequencer encrypts `(sender, txHash)` to that key using ECDH and populates `encryptedSender` in the withdrawal struct. The wire format is `ephemeralPubKey (33 bytes) || ciphertext (52 bytes) || mac (16 bytes)`.
493
+
The sender can optionally specify a `revealTo` public key (compressed secp256k1, 33 bytes) when requesting the withdrawal. If provided, the sequencer encrypts `(sender, txHash)` to that key using ECDH and populates `encryptedSender` in the withdrawal struct. The wire format is `ephemeralPubKey (33 bytes) || nonce (12 bytes) || ciphertext (52 bytes) || tag (16 bytes)` totaling 113 bytes.
491
494
492
495
Two disclosure modes are available:
493
496
@@ -523,9 +526,9 @@ Zone transactions specify which enabled TIP-20 token to use for gas fees via a `
523
526
524
527
Each zone block contains system transactions and user transactions in a fixed order:
525
528
526
-
1.`ZoneInbox.advanceTempo(header, deposits, decryptions)` (optional, at the start of the block). Advances the zone's view of Tempo, processes any pending deposits, and verifies encrypted deposit decryptions. If omitted, the zone's Tempo binding carries forward from the previous block.
529
+
1.`ZoneInbox.advanceTempo(header, deposits, decryptions, enabledTokens)` (optional, at the start of the block). Advances the zone's view of Tempo, enables newly-bridged tokens, processes any pending deposits, and verifies encrypted deposit decryptions. If omitted, the zone's Tempo binding carries forward from the previous block.
527
530
2. User transactions, executed in order.
528
-
3.`ZoneOutbox.finalizeWithdrawalBatch(count)` (required in the final block of a batch, absent in intermediate blocks). Constructs the withdrawal hash chain from pending withdrawals and writes the `withdrawalQueueHash` and `withdrawalBatchIndex` to state. Must be called even if there are zero withdrawals so the batch index advances.
531
+
3.`ZoneOutbox.finalizeWithdrawalBatch(count, blockNumber, encryptedSenders)` (required in the final block of a batch, absent in intermediate blocks). Constructs the withdrawal hash chain from pending withdrawals, populates `encryptedSender` for authenticated withdrawals, and writes the `withdrawalQueueHash` and `withdrawalBatchIndex` to state. Must be called even if there are zero withdrawals so the batch index advances.
529
532
530
533
A batch covers one or more zone blocks, with each batch interval targeting 250 milliseconds. The sequencer controls batch frequency, and intermediate blocks within a batch contain only `advanceTempo` (optional) and user transactions.
531
534
@@ -541,7 +544,7 @@ Zone blocks use a simplified header with fewer fields than a standard Ethereum h
541
544
|`transactionsRoot`|`bytes32`| Root computed over the ordered list of block transactions |
542
545
|`receiptsRoot`|`bytes32`| Root computed over the ordered list of transaction receipts |
543
546
|`number`|`uint64`| Block number |
544
-
|`timestamp`|`uint64`| Block timestamp (must be monotonically increasing) |
547
+
|`timestamp`|`uint64`| Block timestamp (must be non-decreasing) |
545
548
|`protocolVersion`|`uint64`| Zone protocol version |
546
549
547
550
The block hash is `keccak256` of the RLP-encoded header. Batch proofs commit to block hash transitions (`prevBlockHash` to `nextBlockHash`), not raw state roots, so the proof covers the full header structure.
@@ -576,15 +579,16 @@ If a block omits `advanceTempo`, the Tempo binding carries forward from the prev
576
579
577
580
### Storage Reads
578
581
579
-
`TempoState` provides `readTempoStorageSlot(account, slot)` for reading storage from any Tempo contract. This function is restricted to zone system contracts only: `ZoneInbox`, `ZoneOutbox`, and `ZoneConfig`. User transactions cannot call it.
582
+
`TempoState` provides `readTempoStorageSlot(account, slot)` for reading storage from any Tempo contract. This function is restricted to zone system contracts (`ZoneInbox`, `ZoneOutbox`, `ZoneConfig`). User transactions cannot call it.
580
583
581
584
The function is a precompile stub. The actual storage reads are performed by the zone node and validated against the `tempoStateRoot` from the finalized header. The prover includes Merkle proofs for each unique account and storage slot accessed by system contracts during the batch.
582
585
583
-
System contracts use storage reads for:
586
+
Current callers:
584
587
588
+
-`ZoneInbox`: `currentDepositQueueHash` and encryption keys from the portal
585
589
-`ZoneConfig`: sequencer address, token registry from the portal
586
-
-`ZoneInbox`: `currentDepositQueueHash` from the portal
587
-
-`TIP403Registry`: policy state from Tempo
590
+
591
+
TIP-403 policy authorization on the zone is handled by a dedicated read-only proxy precompile (at the same address as the L1 `TIP403Registry`), which resolves policy queries via the zone node's policy provider rather than calling `readTempoStorageSlot` directly.
function finalizeWithdrawalBatch(uint256 count) external returns (bytes32 withdrawalQueueHash);
1185
+
function finalizeWithdrawalBatch(uint256 count, uint64 blockNumber, bytes[] calldata encryptedSenders)
1186
+
external returns (bytes32 withdrawalQueueHash);
1174
1187
}
1175
1188
```
1176
1189
@@ -1197,15 +1210,17 @@ Deployed at the same address as on Tempo. Read-only on the zone. Its `isAuthoriz
1197
1210
1198
1211
## Network Upgrades and Hard Fork Activation
1199
1212
1213
+
> **Note:** The verifier rotation and protocol version mechanisms described below are the target design. The current `ZonePortal` implementation declares `verifier` as `immutable`, so the rotation mechanism is not yet implemented. This section will be updated when the upgrade contracts are deployed.
1214
+
1200
1215
Zones activate hard fork upgrades in lockstep with Tempo using same-block activation. The trigger is the Tempo block number: the zone block whose `advanceTempo` imports the fork Tempo block uses the new execution rules for its entire scope.
1201
1216
1202
-
The portal maintains two verifier slots (`verifier` and `forkVerifier`). At each fork, verifiers rotate: the previous fork verifier is promoted to `verifier`, and the new fork verifier takes the `forkVerifier` slot. At most two verifiers are active at any time. The `IVerifier` interface is unchanged across forks; new proof parameters are passed via the opaque `verifierConfig` bytes.
1217
+
The portal will maintain two verifier slots (`verifier` and `forkVerifier`). At each fork, verifiers rotate: the previous fork verifier is promoted to `verifier`, and the new fork verifier takes the `forkVerifier` slot. At most two verifiers are active at any time. The `IVerifier` interface is unchanged across forks; new proof parameters are passed via the opaque `verifierConfig` bytes.
1203
1218
1204
-
`ZoneFactory`maintains a `protocolVersion` counter incremented at each fork. Zone nodes embed the highest protocol version they support and halt cleanly if the imported Tempo block bumps `protocolVersion` beyond their supported version, preventing an outdated node from producing blocks under incorrect rules.
1219
+
`ZoneFactory`will maintain a `protocolVersion` counter incremented at each fork. Zone nodes embed the highest protocol version they support and halt cleanly if the imported Tempo block bumps `protocolVersion` beyond their supported version, preventing an outdated node from producing blocks under incorrect rules.
1205
1220
1206
1221
No onchain action is required from zone operators. The new verifier is deployed and rotated as part of the Tempo hard fork. Operators upgrade their zone node binary and prover program before the fork; when the fork Tempo block arrives, the node activates new rules automatically.
1207
1222
1208
-
The portal enforces a `forkActivationBlock` cutoff where batches targeting the old `verifier` must have `tempoBlockNumber < forkActivationBlock`. This prevents post-fork batches from being submitted against old verification rules.
1223
+
The portal will enforce a `forkActivationBlock` cutoff where batches targeting the old `verifier` must have `tempoBlockNumber < forkActivationBlock`. This prevents post-fork batches from being submitted against old verification rules.
1209
1224
1210
1225
The Tempo hard fork block executes the following as system transactions:
0 commit comments