# Signet - Full Documentation > Signet is a pragmatic Ethereum rollup with sustainable economic incentives Last updated: 2026-04-07 ## Network Configuration (Parmigiana Testnet) | Property | Value | |----------|-------| | Rollup Chain ID | 88888 | | Host Chain ID | 3151908 | | Rollup RPC | https://rpc.parmigiana.signet.sh | | Host RPC | https://host-rpc.parmigiana.signet.sh | | Explorer | https://explorer.parmigiana.signet.sh | ### Contracts (Host) - Zenith: `0x143A5BE4E559cA49Dbf0966d4B9C398425C5Fc19` - HostOrders: `0x96f44ddc3Bc8892371305531F1a6d8ca2331fE6C` - Passage: `0x28524D2a753925Ef000C3f0F811cDf452C6256aF` - Transactor: `0x0B4fc18e78c585687E01c172a1087Ea687943db9` ### Contracts (Rollup) - RollupOrders: `0x000000000000007369676e65742d6f7264657273` - RollupPassage: `0x0000000000007369676e65742d70617373616765` - WUSD: `0x0000000000000000007369676e65742D77757364` ================================================================================ ## Documentation -------------------------------------------------------------------------------- ### Authentication URL: https://test.signet.sh/docs/block-builders/run-a-builder/authentication/ How to configure OAuth2 authentication for sequencer co-signatures and bundle relay access. -------------------------------------------------------------------------------- # Authentication ## Overview Authentication will be required for the following behaviors: - Getting a sequencer co-signature on a built block. - Retrieving bundles from the bundle relay. Authentication will be performed using a standard OAuth2 client credential grant and then the access token you receive can be used to authorize all requests to the sequencer and bundle relay. ## OAuth Identity Provider Reference ### Havarti | | | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Issuer | [`https://auth.havarti.signet.sh/realms/master`](https://auth.havarti.signet.sh/realms/master) | | OAuth `.well-known` URL | [`https://auth.havarti.signet.sh/realms/master/.well-known/openid-configuration`](https://auth.havarti.signet.sh/realms/master/.well-known/openid-configuration) | | Authorize Endpoint | [`https://auth.havarti.signet.sh/realms/master/protocol/openid-connect/auth`](https://auth.havarti.signet.sh/realms/master/protocol/openid-connect/auth) | | Token Endpoint | [`https://auth.havarti.signet.sh/realms/master/protocol/openid-connect/token`](https://auth.havarti.signet.sh/realms/master/protocol/openid-connect/token) | ## Authenticating Using `curl` First off a basic example of getting an OAuth2 access token and using it to authenticate any of our secured API's ### Obtain an Access Token Make a POST request to the token endpoint with your client credentials. ```bash curl --request POST \ --data grant_type=client_credentials \ --data client_id=${CLIENT_ID} \ --data client_secret=${CLIENT_SECRET} \ --data audience="https://transactions.parmigiana.signet.sh" https://auth.havarti.signet.sh/realms/master/protocol/openid-connect/token ``` ### Use the Access Token to Call Protected APIs Once you receive the access token, include it in the `Authorization` header as a Bearer token. The access_token that is returned should be base64 encoded, and should remain base64 encoded when passed via the Authorization header ```bash ACCESS_TOKEN="your_access_token" curl -H "Authorization: Bearer $ACCESS_TOKEN" \ https://transactions.parmigiana.signet.sh ``` **Parameters:** - `-H "Authorization: Bearer $ACCESS_TOKEN"`: Sets the `Authorization` header with the access token stored in an environment variable ## Authenticating in Rust ### Prerequisites Add the following dependencies to your `Cargo.toml` file: ```toml [dependencies] oauth2 = { version = "4" } reqwest = { version = "0.11", features = ["json", "native-tls"] } tokio = { version = "1", features = ["full", "macros", "rt-multi-thread"] } ``` ### Example Code ```rust use oauth2::basic::BasicClient; use oauth2::{AuthUrl, ClientId, ClientSecret, TokenResponse, TokenUrl}; use oauth2::reqwest::async_http_client; use reqwest::Client; use std::env; use tokio; #[tokio::main] async fn main() -> Result<(), Box> { // Retrieve client ID and secret from environment variables let client_id = ClientId::new( env::var("CLIENT_ID").expect("Missing CLIENT_ID environment variable"), ); let client_secret = ClientSecret::new( env::var("CLIENT_SECRET").expect("Missing CLIENT_SECRET environment variable"), ); // OAuth2 provider URLs let auth_url = AuthUrl::new("https://auth.havarti.signet.sh/authorize".to_string())?; let token_url = TokenUrl::new("https://auth.havarti.signet.sh/oauth/token".to_string())?; // Set up the OAuth2 client let client = BasicClient::new( client_id, Some(client_secret), auth_url, Some(token_url), ); // Perform the client credentials grant let token = client .exchange_client_credentials() // Add the required `audience` param .add_extra_param("audience", "https://transactions.parmigiana.signet.sh") .request(async_http_client)?; let access_token = token.access_token().secret(); // Use the access token to make an API call let api_client = Client::new(); let response = api_client .get("https://transactions.parmigiana.signet.sh/get-bundles") .bearer_auth(access_token) .send() .await?; Ok(()) } ``` -------------------------------------------------------------------------------- ### Build from source URL: https://test.signet.sh/docs/block-builders/run-a-builder/install-and-run-a-node/build-from-source/ How to clone, compile, and run the Signet node from source code. -------------------------------------------------------------------------------- # Build From Source You must have a running consensus client that is accessible to the Signet client. ## Installation 1. Clone the repository ```bash git clone https://github.com/init4tech/signet.git ``` 2. Build the binary ```bash cargo build --release --bin signet ``` 3. Download a binary from [github releases](https://github.com/init4tech/signet/releases) 4. Configure the [environment variables](/docs/block-builders/run-a-builder/install-and-run-a-node/environment-variables/) as needed 5. Copy the binary from the release to a location in your users path ```bash tar -xzf signet-client-v0.1.0-alpha-1 signet cp signet /usr/local/bin ``` 6. Run Signet ```bash signet node \ --chain parmigiana \ --authrpc.jwtsecret /path/to/your/jwt.secret \ --http \ --http.addr 127.0.0.1 \ --http.api eth,net,trace,txpool,web3,rpc,debug,ots ``` -------------------------------------------------------------------------------- ### Environment variables URL: https://test.signet.sh/docs/block-builders/run-a-builder/environment-variables/ Configuration reference for all environment variables used by the Signet builder. -------------------------------------------------------------------------------- # Environment Variables The Builder is configured via environment variables. The following values are supported for configuration. | Key | Required | Description | | ----------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------- | | `HOST_CHAIN_ID` | Required | Host-chain ID (e.g. 3151908) | | `RU_CHAIN_ID` | Required | Rollup-chain ID (e.g. 88888) | | `HOST_RPC_URL` | Required | RPC endpoint for the host chain | | `ROLLUP_RPC_URL` | Required | RPC endpoint for the rollup chain | | `TX_POOL_URL` | Required | Transaction pool URL (must end with /) | | `FLASHBOTS_ENDPOINT` | Optional | When configured, the Builder will send Signet blocks to this URL as transaction bundles | | `TX_BROADCAST_URLS` | Optional | Additional endpoints for blob txs (comma-separated, slash required) | | `ZENITH_ADDRESS` | Required | Zenith contract address | | `BUILDER_HELPER_ADDRESS` | Required | Builder helper contract address | | `QUINCEY_URL` | Required | Remote sequencer signing endpoint | | `BUILDER_PORT` | Required | HTTP port for the Builder (default: 8080) | | `SEQUENCER_KEY` | Required | AWS KMS key ID _or_ local private key for sequencer signing | | `BUILDER_KEY` | Required | AWS KMS key ID _or_ local private key for builder signing | | `BUILDER_REWARDS_ADDRESS` | Required | Address receiving builder rewards | | `ROLLUP_BLOCK_GAS_LIMIT` | Optional | Override for block gas limit | | `CONCURRENCY_LIMIT` | Optional | Max concurrent tasks the simulator uses | | `OAUTH_CLIENT_ID` | Required | Oauth client ID for the builder | | `OAUTH_CLIENT_SECRET` | Required | Oauth client secret for the builder | | `OAUTH_AUTHENTICATE_URL` | Required | Oauth authenticate URL for the builder for performing OAuth logins | | `OAUTH_TOKEN_URL` | Required | Oauth token URL for the builder to get an Oauth2 access token | | `AUTH_TOKEN_REFRESH_INTERVAL` | Required | The OAuth token refresh interval in seconds. | | `CHAIN_NAME` | Required | The name of the chain (e.g. `parmigiana`) | -------------------------------------------------------------------------------- ### Fetching transactions URL: https://test.signet.sh/docs/searchers/fetching-transactions/ How to fetch transactions stored on Signet's transaction cache. -------------------------------------------------------------------------------- The Signet transaction cache Signet's transaction cache stores pending transactions, orders and bundles submitted to the network, providing MEV searchers with a stream of opportunities without having to run their orderflow infrastructure. We'll focus on the basics of fetching transactions. Transactions can be fetched from Signet's transaction cache. Fetching transactions is easy with Signet's Transaction Cache Client. Consult the [Parmigiana Quickstart](/docs/build-on-signet/parmigiana/) for any other RPC endpoints or contract addresses you might need. ## Setup Add the required Signet crates: ```bash cargo add signet-tx-cache ``` ## Fetching Transactions Create a `TxCache` client and fetch transactions: ```rust use signet_tx_cache::TxCache; let cache = TxCache::parmigiana(); // `get_transactions` takes an optional cursor parameter. // Start with `None` to fetch the first page. let response = cache.get_transactions(None).await?; for tx in &response.transactions { println!("Transaction: {}", tx.tx_hash()); } ``` The cache returns up to 50 transactions per request as a list of [`TxEnvelope`](https://docs.rs/alloy/latest/alloy/consensus/type.TxEnvelope.html) objects. You can use these transactions to simulate, analyze, or build bundles. Transactions are ordered by their effective gas price, so the highest-paying transactions appear first. They are only syntactically validated, which means transactions might fail during EVM execution. ## Pagination The cache uses cursor-based pagination. If more transactions are available, the response will include a cursor. This cursor can be passed into the `get_transactions` method to fetch the next page: ```rust let mut all_transactions = Vec::new(); let mut cursor = None; loop { let response = cache.get_transactions(cursor).await?; all_transactions.extend(response.transactions.clone()); if response.has_more() { cursor = response.next_cursor; } else { break; } } ``` -------------------------------------------------------------------------------- ### Getting transactions and bundles URL: https://test.signet.sh/docs/block-builders/customizing-a-builder/getting-transactions-and-bundles-for-a-block/ How to retrieve transactions and bundles from the transaction cache for block building. -------------------------------------------------------------------------------- # Getting Transactions and Bundles The transaction cache offers endpoints for getting simple transactions and Flashbots-style transaction bundles. Fetching bundles requires authentication. This is because Builders are only allowed to build blocks for their assigned slots. See [Authentication](/docs/block-builders/run-a-builder/authentication/) for details. ## Transaction cache basics: - **API Endpoint**: `transactions.api.signet.sh` - **Cache Duration**: 10 minutes - **Authentication:** Authentication is required to retrieve bundles, but not to retrieve transactions. ## API Endpoints ### Get Transactions ```http GET /transactions ``` Returns a list of transactions available for inclusion in a block. ### Get Bundles ```http GET /bundles ``` Returns a list of bundles available for inclusion in a block. Requires authentication. -------------------------------------------------------------------------------- ### Bundle guarantees URL: https://test.signet.sh/docs/block-builders/customizing-a-builder/bundle-guarantees/ Ordering, atomicity, and revertibility guarantees for Flashbots-style transaction bundles. -------------------------------------------------------------------------------- # Bundle Guarantees Signet bundles are [Flashbots-style](https://docs.flashbots.net/flashbots-protect/additional-documentation/bundle-cache) bundles of transactions wrapped with a `host_fills` field. When building blocks containing Signet orders, the atomicity constraints apply to `host_fills` as well, meaning that if a `host_fill` is included and no corresponding rollup transaction is included, it would be considered invalid. ## Bundle Guarantees Block Builders should respect the following guarantees around bundles when building blocks. * **Ordering**: The transaction ordering in a bundle must be preserved. * **Atomicity**: Bundles won't be split up and will be applied as a contiguous block of transactions or won't be applied at all. * **Revertibility**: Transactions in a bundle won't revert unless explicitly marked as revertible. Transactions from the cache can be treated normally and included as seen fit. -------------------------------------------------------------------------------- ### Docker URL: https://test.signet.sh/docs/block-builders/run-a-builder/install-and-run-a-node/docker/ How to run the Signet node using the official Docker image. -------------------------------------------------------------------------------- # Docker You must have a running consensus client that is accessible to the Signet client. ## Installation 1. Pull image from Github Container Repository ```bash docker pull ghcr.io/init4tech/signet:latest ``` 2. Run the container, specifying the [environment variables](/docs/block-builders/run-a-builder/install-and-run-a-node/environment-variables/) as needed ```bash docker run -d \ -e BLOB_EXPLORER_URL=value \ -e SIGNET_STATIC_PATH=value \ -e SIGNET_DATABASE_PATH=value \ -e IPC_ENDPOINT=value \ -e RPC_PORT=value \ -e WS_RPC_PORT=value \ -e IPC_ENDPOINT=value \ -e TX_FORWARD_URL=value \ -e GENESIS_JSON_PATH=value \ -e BASE_FEE_RECIPIENT=value \ -e SIGNET_CL_URL=value \ -e SIGNET_PYLON_URL=value \ -e HOST_START_TIMESTAMP=value \ -e HOST_SLOT_OFFSET=value \ -e HOST_SLOT_DURATION=value ghcr.io/init4tech/signet:latest ``` -------------------------------------------------------------------------------- ### Signed orders URL: https://test.signet.sh/docs/searchers/signed-orders/ How to construct token transfers using Permit2 integration with intent-based orders and user signatures. -------------------------------------------------------------------------------- # Signed Orders Signing Orders Signet's Permit2 integration enhances token transfers by enabling intent-based orders with user signatures and Filler submissions. ## Constructing Token Transfers **Assemble Data** Create the `outputs` array specifying the tokens, amounts, recipients, and destination chain IDs. Construct the `permit` object listing permitted tokens and amounts, along with the `nonce` and `deadline`. **Generate Witness Hash** Hash the `outputs` array to create a witness hash, ensuring the integrity of the transaction details. **Hash Permit Data** Combine the `permit` data with the witness hash and hash the result. This step binds the permit to the specific transaction details. **Sign Data and Encode Signature** Sign the final hashed data using your private key. ### JSON Example ```json { "outputs": [ { "token": "0xtokenaddress", "amount": 100000, "recipient": "0xrecipientaddress", "chainId": 17000 }, { "token": "0xtokenaddress", "amount": 100000, "recipient": "0xrecipientaddress", "chainId": 17001 } ], "permit": { "permitted": [ { "token": "0xtokenaddress", "amount": 100000 }, { "token": "0xtokenaddress", "amount": 100000 } ], "nonce": 0, "deadline": 123456789 }, "owner": "0xsigneraddress", "signature": "0xpackedVRSsignature" } ``` ## Submitting a Signed Order Use the `initiatePermit2` function to submit the signed order. Pass the `outputs` array and the `permit2` object containing the permit data, owner address, and signature. ### Solidity Function Interface: InitiatePermit2 ```solidity function initiatePermit2( address tokenRecipient, // Filler-submitted Output[] memory outputs, // signed OrdersPermit2.Permit2Batch calldata permit2 // signed ) external; ``` Ensure that the `outputs` and `permit2` structs are correctly formatted and signed and validate the `nonce` to prevent replay attacks and check the `deadline` for transaction validity. ## Filling Orders Use the `fillPermit2` function to process the order and transfer the specified tokens. ### Solidity Function Interface: `fillPermit2` ```solidity function fillPermit2( Output[] memory outputs, OrdersPermit2.Permit2Batch calldata permit2 ) external; ``` The `permit.permitted` array acts as the `outputs` and must match the order exactly for the transaction to proceed. Ensure that the format and structures used for filling orders are consistent with those used for submitting orders. ## Solidity Structs ### Struct: `Output` ```solidity struct Output { address token; // ERC20 token address on the destination chain uint256 amount; // Amount of the token to be sent address recipient; // Address to receive the output tokens uint32 chainId; // Destination chain ID for the Output } ``` ### Struct: `Permit2Batch` ```solidity struct Permit2Batch { ISignatureTransfer.PermitBatchTransferFrom permit; address owner; bytes signature; } ``` ### Struct: `PermitBatchTransferFrom` ```solidity struct PermitBatchTransferFrom { TokenPermissions[] permitted; uint256 nonce; uint256 deadline; } ``` ### Struct: `TokenPermissions` ```solidity struct TokenPermissions { address token; // ERC20 token address uint256 amount; // Maximum amount that can be spent } ``` Non-linear nonce: Each nonce is unique and does not have to follow a sequential order. This design prevents replay attacks and increases transaction security. -------------------------------------------------------------------------------- ### Compiled binaries URL: https://test.signet.sh/docs/block-builders/run-a-builder/install-and-run-a-node/compiled-binaries/ How to install and run the Signet node from pre-compiled binaries. -------------------------------------------------------------------------------- # Compiled Binaries You must have a running consensus client that is accessible to the Signet client. ## Installation 1. Download binary from github releases 2. Configure the [environment variables](/docs/block-builders/run-a-builder/install-and-run-a-node/environment-variables/) as needed 3. Copy the binary from the release to a location in your users path ```bash tar xzf signet-client-v0.1.0-alpha-1 signet cp signet /usr/local/bin ``` 4. Run Signet ```bash signet node \ --chain parmigiana \ --authrpc.jwtsecret /path/to/your/jwt.secret \ --http \ --http.addr 127.0.0.1 \ --http.api eth,net,trace,txpool,web3,rpc,debug,ots ``` -------------------------------------------------------------------------------- ### Filler URL: https://test.signet.sh/docs/searchers/filler/ Build an order filler bot using the signet-orders crate -------------------------------------------------------------------------------- # Filler The `Filler` struct from [`signet-orders`](https://docs.rs/signet-orders/latest/signet_orders/) orchestrates the full order-filling pipeline: fetching pending orders from a source, signing [Permit2](https://docs.uniswap.org/contracts/permit2/overview) fills, and submitting them as bundles. It is the main building block for writing a Signet filler bot. Example implementation The signet-filler repository is an example filler built on top of Filler and FeePolicySubmitter. It demonstrates order filtering, metrics, provider setup, and the overall structure of a filler service. ## Setup ```bash cargo add signet-orders signet-types signet-constants signet-tx-cache cargo add alloy --features provider-http,signers cargo add futures-util ``` ## Architecture `Filler` is generic over three type parameters: - **`Sign`**: Any [alloy `Signer`](https://docs.rs/alloy/latest/alloy/signers/trait.Signer.html) — signs Permit2 fill messages - **`Source`**: An [`OrderSource`](https://docs.rs/signet-orders/latest/signet_orders/trait.OrderSource.html) — provides a stream of pending orders (e.g. from the tx cache) - **`Submit`**: A [`FillSubmitter`](https://docs.rs/signet-orders/latest/signet_orders/trait.FillSubmitter.html) — handles transaction construction, gas pricing, and bundle submission ``` OrderSource ──▶ Filler ──▶ FillSubmitter ──▶ BundleSubmitter (fetch) (sign) (build txs) (submit bundle) ``` The crate provides [`TxCache`](https://docs.rs/signet-tx-cache/latest/signet_tx_cache/) as a ready-made `OrderSource` and `BundleSubmitter`, and [`FeePolicySubmitter`](https://docs.rs/signet-orders/latest/signet_orders/struct.FeePolicySubmitter.html) as a `FillSubmitter` that handles gas pricing and bundle construction. ## Creating a Filler ```rust use alloy::providers::ProviderBuilder; use signet_constants::parmigiana; use signet_orders::{FeePolicySubmitter, Filler, FillerOptions}; use signet_tx_cache::TxCache; let signer = /* your alloy Signer */; let wallet = /* EthereumWallet wrapping the same key */; // Connect providers with gas estimation and wallet signing let ru_provider = ProviderBuilder::new() .wallet(wallet.clone()) .connect("https://rpc.parmigiana.signet.sh") .await?; let host_provider = ProviderBuilder::new() .wallet(wallet) .connect("https://eth.llamarpc.com") .await?; let tx_cache = TxCache::parmigiana(); let constants = parmigiana::system_constants(); // FeePolicySubmitter builds fill + initiate transactions and wraps them in a // SignetEthBundle before forwarding to the BundleSubmitter (here, the tx cache). let submitter = FeePolicySubmitter::new( ru_provider, host_provider, tx_cache.clone(), constants.clone(), ); let filler = Filler::new( signer, tx_cache, submitter, constants, FillerOptions::new(), ); ``` ## FillerOptions `FillerOptions` lets you tune fill signing behavior: - **`deadline_offset`** — seconds from now until the Permit2 signature expires. When `None` (default), defaults to 12 seconds. - **`nonce`** — explicit Permit2 nonce. When `None` (default), a fresh nonce is generated from the current timestamp in microseconds. ```rust let options = FillerOptions::new() .with_deadline_offset(30) // 30 second deadline .with_nonce(42); // explicit nonce ``` ## Fetching and Filling Orders ### Fetch orders as a stream `get_orders()` returns a `Stream` of `SignedOrder`s. You can filter, collect, or process them however you like: ```rust use futures_util::{StreamExt, TryStreamExt}; let orders: Vec<_> = filler .get_orders() .try_filter(|order| { // Apply your own filtering logic std::future::ready(is_profitable(order)) }) .try_collect() .await?; ``` ### Fill a batch of orders `fill()` signs Permit2 fills for the orders, builds transactions, and submits the bundle in one call: ```rust match filler.fill(orders).await { Ok(response) => println!("Bundle submitted: {}", response.id), Err(error) => eprintln!("Fill failed: {error}"), } ``` ### Sign fills without submitting For more control, use `sign_fills()` to get back an `OrdersAndFills` struct that pairs orders with their signed fills: ```rust let orders_and_fills = filler.sign_fills(orders).await?; // Inspect before submitting println!("Signer: {}", orders_and_fills.signer_address()); println!("Orders: {}", orders_and_fills.orders().len()); println!("Fills per chain: {}", orders_and_fills.fills().len()); ``` ## Implementing Custom Traits ### OrderSource Provide orders from a custom source: ```rust use futures_util::Stream; use signet_orders::OrderSource; use signet_types::SignedOrder; struct MyOrderSource; impl OrderSource for MyOrderSource { type Error = MyError; fn get_orders(&self) -> impl Stream -------------------------------------------------------------------------------- ### Environment variables URL: https://test.signet.sh/docs/block-builders/run-a-builder/install-and-run-a-node/environment-variables/ Configuration reference for all environment variables used by the Signet node client. -------------------------------------------------------------------------------- # Environment Variables The following environment variables can be used to configure various aspects of the `signet` node client. | Environment Variable | Required | Description | | ---------------------- | -------------------------------------------------- | --------------------------------------------------------------------------- | | `BLOB_EXPLORER_URL` | Required | URL of a blob explorer | | `SIGNET_STATIC_PATH` | Required | Filesystem path to where the static_files directory should be located | | `SIGNET_DATABASE_PATH` | Required | Filesystem path to where the node should store its database | | `IPC_ENDPOINT` | Optional | Filesystem path for the .ipc file | | `GENESIS_JSON_PATH` | Required | Path on the filesystem for the genesis file | | `RPC_PORT` | Required | Port to be used for the rollup node http json-rpc requests | | `WS_RPC_PORT` | Required | Port to be used for the rollup node's WebSocket connections | | `TX_FORWARD_URL` | Optional | URL for the transaction cache API | | `SIGNET_CL_URL` | Optional | URL to the consensus layer for fetching blobs and other CL responsibilities | | `SIGNET_PYLON_URL` | Optional | URL to the Pylon node for blob storage | | `HOST_START_TIMESTAMP` | Required | The host chain's start timestamp for slot calculation purposes | | `HOST_SLOT_OFFSET` | Required | The host chain's slot offset | | `HOST_SLOT_DURATION` | Required | The host chain's slot duration | | `RUST_LOG` | Optional | Standard rust environment variable for logging | -------------------------------------------------------------------------------- ### Getting a sequencer signature URL: https://test.signet.sh/docs/block-builders/customizing-a-builder/getting-a-sequencer-signature/ How to obtain a sequencer co-signature for your block using the Sequencer API. -------------------------------------------------------------------------------- # Getting a Sequencer Signature Blocks must be cosigned by the Sequencer. The Sequencer blindly signs any number of candidate blocks for the current Builder via a simple API. The Sequencer API accepts a [`SignRequest`][signrequest] via a `POST` call to the `/signBlock` endpoint, and returns a [`SignResponse`][signresponse]. For details on calculating the `contents` hash, see the [rust builder example](https://github.com/init4tech/builder/blob/main/src/quincey.rs). The sequencer is allowed to modify the returned copy of the SignRequest. This is to allow the sequencer to set a specific gas_limit. It currently does not modify the request before returning it, but may do so in the future. ## Slot Timing Quincey follows a round-robin sequencing approach, allowing builders to request block signatures according to their spot in the rotation. Each slot starts at the timestamp of the latest block and extends for 12 seconds. Sequencer requests must be made in the first 10 seconds of the builder's assigned slot, as there is a 2 second buffer at the end of the slot to prevent timing games and ensure enough time for the submission process. For this reason, the Builder [defaults to a slightly longer 3 second cutoff](https://github.com/init4tech/builder/blob/main/src/config.rs#L158-L163) at the end of its assigned slot, at which point it begins the signing and submission process for the block it built. See the [deadline calculation code](https://github.com/init4tech/builder/blob/main/src/tasks/block/sim.rs#L228-L253) for deeper details. ## API Endpoint ```http POST /signBlock ``` - **Request Body**: [SignRequest] JSON object. - **Response**: [SignResponse] JSON object containing the sequencer's signature. [signrequest]: https://docs.rs/zenith-types/latest/zenith_types/struct.SignRequest.html [signresponse]: https://docs.rs/zenith-types/latest/zenith_types/struct.SignResponse.html -------------------------------------------------------------------------------- ### Parmigiana quickstart URL: https://test.signet.sh/docs/build-on-signet/parmigiana/ How to build on Signet’s latest public testnet (Parmigiana). -------------------------------------------------------------------------------- # Parmigiana quickstart Parmigiana Testnet Host Chain ID 3151908 Rollup Chain ID 88888 Deploy Height 0 Native Gas Token USD Rollup RPC rpc.parmigiana.signet.sh Host RPC host-rpc.parmigiana.signet.sh Rollup Explorer explorer.parmigiana.signet.sh Host Explorer explorer-host.parmigiana.signet.sh TX Cache API transactions.parmigiana.signet.sh Parmigiana is Signet's public testnet for rollup and application experimentation. This page contains the faucet, RPC endpoints, and contract addresses you need to get started. These constants are also available to Rust code via the [`signet-constants`](https://docs.rs/signet-constants/latest/signet_constants/) crate. If you need to test applications that interact with both host and rollup chains, [please reach out](mailto:hello@init4.technology). Get testnet funds Select assets to fund USD ETH This faucet requires JavaScript for wallet integration. To get testnet funds without JavaScript: Use the Parmigiana Faucet web app Or fund via CLI:cast send 0x28524D2a753925Ef000C3f0F811cDf452C6256aF "enter(address)" YOUR_ADDRESS \ --value 0.1ether \ --rpc-url https://host-rpc.parmigiana.signet.sh \ --private-key YOUR_KEY Available per request: 1.00 USD + 0.01 ETH. One-Click Setup Connects wallet, adds network, funds 1.00 USD + 0.01 ETH. Wallet Address Funded Wallets USD ETH ## Host System Contracts | Contract | Address | | ---------------------- | ---------------------------------- | | [Zenith] | 0x143A5BE4E559cA49Dbf0966d4B9C398425C5Fc19 | | [HostOrders] | 0x96f44ddc3Bc8892371305531F1a6d8ca2331fE6C | | [Passage][Passage-src] | 0x28524D2a753925Ef000C3f0F811cDf452C6256aF | | [Transactor] | 0x0B4fc18e78c585687E01c172a1087Ea687943db9 | | [WETH][HostWeth] | 0xD1278f17e86071f1E658B656084c65b7FD3c90eF | | [WBTC][HostWbtc] | 0xfb29f7d7a4ce607d6038d44150315e5f69bea08a | | [USDC][HostUsdc] | 0x65fb255585458de1f9a246b476aa8d5c5516f6fd | | [USDT][HostUsdt] | 0xb9df1b911b6cf6935b2a918ba03df2372e94e267 | ## Rollup System Contracts | Contract | Address | | --------------- | ------------------------------------- | | [RollupOrders] | 0x000000000000007369676e65742d6f7264657273 | | [RollupPassage] | 0x0000000000007369676e65742d70617373616765 | | [WETH][RollupWeth] | 0x0000000000000000007369676e65742d77657468 | | [WBTC][RollupWbtc] | 0x0000000000000000007369676e65742D77627463 | ## Rollup Utility Contracts | Contract | Address | | ----------------------------------- | --------------------------------------------- | | [WUSD (Wrapped Native) Asset] | 0x0000000000000000007369676e65742D77757364 | | [Permit2] | 0x000000000022D473030F116dDEE9F6B43aC78BA3 | | [Gnosis Safe Factory] | 0x8ff5C1D5233CA055cD536b2b87294d17f9160801 | | [Gnosis SafeL2] | 0x2f2965efaCFc64Fb85dF1902260eB25C0c996195 | | [Safe CompatibilityFallbackHandler] | 0xe59838EB7f251489b50940BD640326215420B936 | | [Deterministic Deployer] | 0x4e59b44847b379578588920cA78FbF26c0B4956C | [Zenith]: https://github.com/init4tech/zenith/blob/main/src/Zenith.sol [HostOrders]: https://github.com/init4tech/zenith/blob/main/src/orders/HostOrders.sol [Passage-src]: https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol [Transactor]: https://github.com/init4tech/zenith/blob/main/src/Transactor.sol [RollupOrders]: https://github.com/init4tech/zenith/blob/main/src/orders/RollupOrders.sol [RollupPassage]: https://github.com/init4tech/zenith/blob/main/src/passage/RollupPassage.sol [HostWeth]: https://github.com/init4tech/simple-erc20/blob/main/src/SimpleERC20.sol [HostWbtc]: https://github.com/init4tech/simple-erc20/blob/main/src/SimpleERC20.sol [HostUsdc]: https://github.com/init4tech/simple-erc20/blob/main/src/SimpleERC20.sol [HostUsdt]: https://github.com/init4tech/simple-erc20/blob/main/src/SimpleERC20.sol [RollupWeth]: https://github.com/islishude/uniswapv2-solc0.8/blob/main/contracts/test/WETH9.sol [RollupWbtc]: https://github.com/islishude/uniswapv2-solc0.8/blob/main/contracts/test/WETH9.sol [WUSD (Wrapped Native) Asset]: https://github.com/islishude/uniswapv2-solc0.8/blob/main/contracts/test/WETH9.sol [Permit2]: https://docs.uniswap.org/contracts/permit2/overview [Gnosis Safe Factory]: https://github.com/safe-global/safe-smart-account/blob/main/contracts/proxies/SafeProxyFactory.sol [Gnosis SafeL2]: https://github.com/safe-global/safe-smart-account/blob/main/contracts/Safe.sol [Safe CompatibilityFallbackHandler]: https://github.com/safe-global/safe-smart-account/blob/main/contracts/handler/CompatibilityFallbackHandler.sol [Deterministic Deployer]: https://github.com/Arachnid/deterministic-deployment-proxy ## ABIs Each contract ABI is available as a JSON download: ```bash curl -O https://signet.sh/abis/Passage.abi.json curl -O https://signet.sh/abis/RollupOrders.abi.json curl -O https://signet.sh/abis/HostOrders.abi.json curl -O https://signet.sh/abis/Transactor.abi.json ``` ## Next steps - Bridge assets: [Passage](/docs/build-on-signet/transfers/enter-signet/) - Trigger rollup txs from L1: [Transactor](/docs/build-on-signet/advanced/execute-from-ethereum/) - Build with Orders: [Orders overview](/docs/build-on-signet/transfers/exit-signet/) - Review protocol behavior: [EVM behavior](/docs/learn-about-signet/evm-behavior/) -------------------------------------------------------------------------------- ### Chain configuration URL: https://test.signet.sh/docs/block-builders/run-a-builder/install-and-run-a-node/chain-configuration/ Network configuration values and contract addresses for Parmigiana testnet. -------------------------------------------------------------------------------- # Chain Configuration See [`signet-constants`](https://github.com/init4tech/signet-sdk/blob/main/crates/constants/src/chains/parmigiana.rs) for loading and interacting with genesis files and values. Parmigiana Testnet Host Chain ID 3151908 Rollup Chain ID 88888 Deploy Height 0 Native Gas Token USD Rollup RPC rpc.parmigiana.signet.sh Host RPC host-rpc.parmigiana.signet.sh Rollup Explorer explorer.parmigiana.signet.sh Host Explorer explorer-host.parmigiana.signet.sh TX Cache API transactions.parmigiana.signet.sh See [Parmigiana Quickstart](/docs/build-on-signet/parmigiana/) for complete contract addresses. -------------------------------------------------------------------------------- ### Getting started URL: https://test.signet.sh/docs/build-on-signet/getting-started/ Install dependencies and configure clients for Signet development. -------------------------------------------------------------------------------- New to Signet? Start with [Learn about Signet](/docs/learn-about-signet/) for background on how the system works. Select your language to see the relevant setup instructions. Get testnet tokens from the [Parmigiana quickstart](/docs/build-on-signet/parmigiana/). -------------------------------------------------------------------------------- ### Submitting a block to Ethereum URL: https://test.signet.sh/docs/block-builders/customizing-a-builder/submitting-a-block-to-ethereum/ How to submit rollup blocks to Ethereum using EIP-4844 blobs and the Zenith contract. -------------------------------------------------------------------------------- # Submitting a Block to Ethereum Rollup blocks are submitted to the host chain by calling the Zenith [`submitBlock`](https://github.com/init4tech/zenith/blob/37f386a8465d97f40e3233971c7a7868bbd4e4d9/src/Zenith.sol#L105) function, attaching transaction data in a 4844 blob. ## Code Flows These examples assume one has already [chosen a set of transactions and bundles](/docs/block-builders/customizing-a-builder/getting-transactions-and-bundles-for-a-block/), and [gotten a co-signature from the Sequencer API](/docs/block-builders/customizing-a-builder/getting-a-sequencer-signature/). The builder example has a submission process without host fills that can be referenced for blob construction. For blocks with host fill components, builders should use a multi-call contract to do the following: Call submitBlock as described below Pass each permit2 blob to the Passage contract's fillPermit2 method ## Creating the Blob Transaction 1. [Transform](https://github.com/init4tech/zenith-rs/blob/ab25a183ad5c8b5c2c39aa2443e89380240423f2/crates/builder/src/tasks/submit.rs#L105C9-L111C11) the [`SignResponse`](https://docs.rs/zenith-types/latest/zenith_types/struct.SignResponse.html) into a [`Zenith::BlockHeader`](https://docs.rs/zenith-types/latest/zenith_types/Zenith/struct.BlockHeader.html). ```rust let header = Zenith::BlockHeader { hostBlockNumber: resp.req.host_block_number, rollupChainId: U256::from(self.config.ru_chain_id), gasLimit: resp.req.gas_limit, rewardAddress: resp.req.ru_reward_address, blockDataHash: in_progress.contents_hash(), }; ``` 2. [Encode](https://github.com/init4tech/zenith-rs/blob/ab25a183ad5c8b5c2c39aa2443e89380240423f2/crates/builder/src/tasks/submit.rs#L85) the [`submitBlock`](https://github.com/init4tech/zenith/blob/37f386a8465d97f40e3233971c7a7868bbd4e4d9/src/Zenith.sol#L105) transaction data from the `BlockHeader` & the Sequencer's `Signature` from the `SignResponse` ```rust let data = Zenith::submitBlockCall { header, v, r, s, _4: Default::default() }.abi_encode(); ``` The final unnamed bytes parameter should be an empty bytes string 3. [Encode](https://github.com/init4tech/zenith-rs/blob/da819327dba6e62a084cd99625e561811a31f12f/crates/builder/src/tasks/block.rs#L71) the transactions into a 4844 blob sidecar containing the rlp-encoded transactions. ```rust pub fn encode_blob(&self) -> SidecarBuilder { let mut coder = SidecarBuilder::default(); coder.ingest(self.encode_raw()); coder } ``` Signet blobs use the alloy SimpleCoder blob encoding scheme. This may change in the future. 4. [Attach](https://github.com/init4tech/zenith-rs/blob/da819327dba6e62a084cd99625e561811a31f12f/crates/builder/src/tasks/submit.rs#L118) the blob sidecar to a [`TransactionRequest`](https://docs.rs/alloy-rpc-types/latest/alloy_rpc_types/struct.TransactionRequest.html). ```rust let tx = TransactionRequest::default().with_blob_sidecar(sidecar).with_input(data); ``` 5. Fill in remaining transaction details (including the calldata, which must contain the encoded `submitBlockCall` above). If using a multi-call contract, the input to the multi-call must send the encoded submitBlockCall to the Zenith contract. 6. Submit the constructed transaction to Ethereum. It is CRITICALLY IMPORTANT to use a private transaction relay to submit blocks coupled with fills. Leaking fill transactions or signed permit2 fills may result in loss of building privileges. -------------------------------------------------------------------------------- ### Enter Signet URL: https://test.signet.sh/docs/build-on-signet/transfers/enter-signet/ Move ETH and ERC-20 tokens from Ethereum to Signet via Passage -------------------------------------------------------------------------------- [Passage](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) is the bridge contract on Ethereum that moves assets into Signet. Deposits arrive on the rollup in the same block they're submitted. Passage has two entry points: one for ETH (sent as `msg.value`) and one for ERC-20 tokens (requires a prior token approval). Both take a `rollupRecipient` address that receives the tokens on Signet. Supported assets Signet currently supports bridging ETH, USDC, USDT, and WBTC from Ethereum. Contact the Signet team to add support for additional assets. The Signet node watches for `Enter` and `EnterToken` events on the Passage contract. If the event fired, the deposit was processed -- no additional confirmation is needed on the rollup side. -------------------------------------------------------------------------------- ### Execute from Ethereum URL: https://test.signet.sh/docs/build-on-signet/advanced/execute-from-ethereum/ Execute transactions from Ethereum to Signet with guaranteed inclusion -------------------------------------------------------------------------------- The Transactor contract provides guaranteed, censorship-resistant execution on Signet from Ethereum. Any Ethereum account can call Transactor to trigger a transaction on Signet that builders cannot censor or reorder. ## Overview `Transactor.sol` exposes two function signatures for sending transactions to Signet: ### Default Chain ```solidity function transact( address to, bytes calldata data, uint256 value, uint256 gas, uint256 maxFeePerGas ) external payable ``` This version uses the contract's `defaultRollupChainId` configured at deployment. ### Explicit Chain ```solidity function transact( uint256 rollupChainId, address to, bytes calldata data, uint256 value, uint256 gas, uint256 maxFeePerGas ) external payable ``` Use this version when targeting a specific Signet chain in multi-chain deployments. --- Calling either `transact` function results in a system transaction being issued on Signet **from the address of the caller**. This allows Ethereum contracts to own assets on Signet, and to trigger contract execution on Signet from Ethereum with native authentication. The `value` argument is the amount of USD in wei to send **on the rollup**. USD is the native asset of Signet. This amount will be attached to the Signet transaction. The balance of the originating address on Signet must be sufficient to cover this value. Note See the Address Aliasing section in the EVM Behavior docs for important information on how contract addresses are modified when using the Transactor. Transact events are executed at the **end** of the Signet block. Contract creation via `Transactor` is not currently supported. The Transactor emits a `Transact` event that can be monitored. The Signet node listens for these events directly, so if the event fired, the transaction **was** included in Signet, although the inner call may revert. Use Transactor when... You need guaranteed transaction inclusion You want to trigger Signet actions from Ethereum You're building cross-chain workflows You need censorship resistance Don't use Transactor when... You're just moving assets (use [Passage] instead) Gas cost is a primary concern (direct Signet txs are cheaper) You don't need L1-triggered execution [Passage]: https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol -------------------------------------------------------------------------------- ### FAQ URL: https://test.signet.sh/docs/more-info/faq/ Frequently asked questions about Signet -------------------------------------------------------------------------------- # FAQ What is Signet? Signet is a pragmatic Ethereum rollup designed to offer sustainable economic incentives. It aims to modernize and streamline rollups by simplifying their architecture and focusing on efficiency. How does Signet differ from traditional rollups? Signet differs in several key ways: It doesn't use proving systems or state roots, which reduces computational overhead. It uses market-based cross-chain transfers instead of complex bridging mechanisms. It replaces block auctions and centralized rollup sequencing with a controlled block inclusion mechanism. It introduces conditional transactions for secure, atomic cross-chain operations. How does Signet handle cross-chain transfers? Signet uses market-based mechanisms and conditional transactions for cross-chain transfers. This allows for secure, instant transfers between Ethereum and Signet without the need for lockup periods. See Cross-chain Transfers. Is Signet suitable for all use cases? Signet isn't suitable for all use cases. For example, it's not ideal for users who require light client functionality or certain types of cross-chain interactions that rely on cryptographic proofs. How does Signet ensure fair block production? Instead of using auctions, Signet uses a central sequencer that assigns block production rights in a round-robin style to block builders. This prevents domination by a small number of wealthy builders and promotes fair participation. What tokens are supported for bridging? Signet supports ETH, USDC, USDT, and WBTC for bridging between Ethereum and Signet. Custom assets may be created within Signet but cannot be bridged from Ethereum without coordination with the Signet team. See Moving Assets to Signet for details. What is Parmigiana? Parmigiana is Signet's public testnet for rollup and application experimentation. It includes RPC endpoints, faucet, explorer, and transaction cache infrastructure for development. See Parmigiana Quickstart for network configuration and contract addresses. How does Signet guarantee atomic cross-chain execution? Signet requires cross-chain transfers to be fully executed in the same block on both chains. If the transfer is not fully executed, the transaction is invalid and has no effect on Signet's state—as if the transaction never existed. See Cross-chain Transfers for more details. Do I need to run my own Ethereum or Signet node? No. You can use public RPC endpoints. For the Parmigiana testnet, see the Parmigiana Quickstart for endpoints. For block builders, RPC access can be configured via environment variables—running your own nodes is optional infrastructure. See Environment Variables for builder configuration. What do block builders do in the Signet ecosystem? Block Builders collect user transactions, build blocks, and post those blocks to Ethereum. Some user transactions create swap orders. These orders may trade between Signet and Ethereum, or within Signet. Block builders can chose to fill any number of orders as part of constructing the block. -------------------------------------------------------------------------------- ### Simplifying the rollup URL: https://test.signet.sh/docs/learn-about-signet/simplifying-the-rollup/ An introduction to Signet, init4, and the Signet ecosystem. -------------------------------------------------------------------------------- # Simplifying the rollup Signet is a pragmatic Ethereum rollup with sustainable economic incentives. It offers a new set of ideas, aiming to radically modernize and streamline rollups. No proving systems or state roots, drastically reducing computational overhead Market-based cross-chain transfers for instant asset movement Removes block auctions in favor of a controlled block inclusion mechanism Introduces conditional transactions for secure, atomic cross-chain operations Signet is built by [Init4](https://x.com/init4tech), a research collective building next-generation Ethereum. ## A Brief History of the Rollup Ethereum rollups are the intellectual descendants of a project called [Plasma](https://ethereum.org/en/developers/docs/scaling/plasma/). Plasmas were complex multi-layered chain systems that used intricate proofs to connect to Ethereum. The research community gradually abandoned Plasmas because their proving trade-offs turned out to be unsuitable to real applications. Around the time Plasma was falling out of favor, a transaction batching service for simple payments called [roll_up](https://github.com/barryWhiteHat/roll_up) was being developed. Plasma researchers co-opted the name _rollup_ and shifted their focus to the development of early rollups, while still focusing on the proving systems. Today, many more rollups have been created. All of these projects have carried forward the original Plasma architecture, placing a proving system at the center of the tech stack. Today rollups are mostly categorized by their proving system — zk or optimistic — but that doesn't have to be the case. ## Back to basics Ethereum rollups have always been complex. They have never had an era where they _weren't_ complex. They didn't start simple and evolve; they were born complex and stayed that way. Their core ideas have never been fundamentally challenged. **Signet's thesis is that the complexity isn't necessary.** > A rollup is an opt-in subset of another consensus, keeping a superset of state, via a custom state-transition function. > Defining "rollup" ## Rollups are sandwiches Think of rollups as sandwiches. Current-generation rollups all have the same set of "mandatory ingredients" inherited from their common ancestry. To differentiate, they add more and more "toppings", resulting in increasingly massive sandwich-systems. Signet is the classic grilled cheese of rollups. Bread, butter, and cheese: simple, effective, and satisfying for most users. We're not saying complex rollups aren't for anyone, just that they're not for everyone. ## Signet is just a rollup We built Signet to be straightforward, fast, and affordable. - **Full EVM compatibility**: Deploy smart contracts, connect wallets, farm $YAMs. - **Simple deployment and ops**: Signet is a drop-in update to your existing Ethereum node. No more 4-node `docker-compose` setups to run a rollup. - **Massively higher gas limits**: Eliminating protocol and proving overhead frees up resources for users. -------------------------------------------------------------------------------- ### Bundles URL: https://test.signet.sh/docs/build-on-signet/advanced/bundles/ How to create and submit transaction bundles that execute atomically across Ethereum and Signet. -------------------------------------------------------------------------------- Bundles are ordered sets of transactions that execute atomically. All succeed or all revert. They can span both Signet and Ethereum, enabling cross-chain operations like order fills where both sides must settle in the same block. -------------------------------------------------------------------------------- ### Exit Signet URL: https://test.signet.sh/docs/build-on-signet/transfers/exit-signet/ Move assets from Signet back to Ethereum -------------------------------------------------------------------------------- Create and submit orders to move assets from Signet to Ethereum. For background on the order lifecycle and atomic settlement, see [How orders work](/docs/learn-about-signet/how-orders-work/). ## Order data model Every order has inputs (what the user gives up on Signet) and outputs (what they receive on the destination chain). **Input:** | Field | Description | |-------|-------------| | `token` | ERC-20 address on Signet. Zero address for native USD. | | `amount` | Amount in the token's smallest unit (e.g., wei). | **Output:** | Field | Description | |-------|-------------| | `token` | ERC-20 address on the destination chain. | | `amount` | Amount in the token's smallest unit. | | `recipient` | Delivery address on the destination chain. | | `chainId` | Destination chain ID. | An order can have multiple inputs and multiple outputs across different chains and recipients. The data model is [ERC-7683](https://eips.ethereum.org/EIPS/eip-7683) compliant. ## On-chain vs gasless **On-chain** orders call `RollupOrders.initiate` directly. The user sends a transaction and pays gas. Fillers discover it via `Order` events. **Gasless** orders use Permit2. The user signs an EIP-712 message (no transaction, no gas) and submits it to the [transaction cache](/docs/learn-about-signet/how-orders-work/#the-transaction-cache), where fillers pick it up. Requires a one-time Permit2 token approval. ## Pricing The spread between input and output is the filler's incentive. A user offering 1 WETH on Signet for 0.995 WETH on Ethereum gives the filler 50 basis points (0.5%). If your order isn't getting filled, widen the spread. If it fills instantly every time, you may be offering more than necessary. No fill guarantee Orders guarantee that if the output isn't delivered, nothing happens on Signet. But there's no guarantee a filler will choose to fill your order. Set competitive spreads to attract fillers. ## FAQ **What happens if nobody fills?** The order expires at the deadline. Tokens stay on Signet. Nothing is lost. **Can an order partially fill?** No. The entire output must be delivered, or nothing happens. **Can my user cancel?** On-chain orders created via `initiate` cannot be cancelled -- the deadline is the only expiry mechanism. Gasless Permit2 orders can be cancelled by consuming the Permit2 nonce. **How long should the deadline be?** Shorter deadlines reduce the time funds are committed but give fillers less time to act. Start with 1 minute for testing. -------------------------------------------------------------------------------- ### Glossary URL: https://test.signet.sh/docs/more-info/glossary/ Definitions of key terms and concepts in Signet -------------------------------------------------------------------------------- # Glossary Blind Signing A security feature where the sequencer signs a block without seeing its contents. The sequencer only sees the block's hash and the builder's identity. This prevents selective censorship or manipulation based on block contents. In Signet, the sequencer blind signs every block, ensuring fair and unbiased inclusion. Block Builders Participants who assemble and propose new blocks. They collect pending transactions, organize them to maximize fees, and submit the block for inclusion. Signet assigns block production rights via round-robin rather than auctions. A central sequencer rotates assignment across builders, preventing concentration of block production. Conditional Transactions Transactions that only execute if all specified conditions are met. If any condition fails, the entire transaction is cancelled with no effect on state. In Signet, conditional transactions enable cross-chain transfers: the transfer executes in the same block on both chains, or not at all. State Roots A single hash representing the entire chain state (accounts, balances, contract storage) at a specific block. Any change to any part of the state produces a different root. Signet does not use state roots. See No proofs or state roots. Orders (Signet Orders) Atomic, instant, cross-chain swaps between Signet and Ethereum. Orders specify inputs (what you're providing on Signet) and outputs (the assets you want to receive, the chain, and address for delivery). Orders can be created on-chain via the Orders Contract or off-chain via SignedOrder objects. Cross-chain transfers must be fully executed in the same block on both chains; otherwise, the transaction is invalid and has no effect on Signet's state. See Working with Orders for implementation details. Fillers MEV Searchers who compete to fulfill Orders by providing the output tokens. When a Filler provides the outputs specified in an Order, they receive the Order's inputs. See How Orders Work for more details. Bundles (Signet) Flashbots-style bundles of transactions wrapped with a host_fills field. Host fills must be atomically included with their corresponding rollup transactions. If a host fill is included without its corresponding rollup transaction, the bundle is considered invalid. Block builders must respect ordering (preserved), atomicity (all or nothing), and revertibility (no unexpected reverts) guarantees. See Bundle Guarantees for details. Host Chain / Rollup Chain Terminology used in Signet configuration and APIs. Host Chain refers to Ethereum. Rollup Chain refers to Signet. On the Parmigiana testnet, Rollup Chain ID is 88888. See Parmigiana Quickstart for network configuration. Sequencer The entity responsible for co-signing blocks in Signet. Unlike most rollups where the sequencer orders transactions directly, Signet's sequencer delegates ordering to block builders and blind signs the result. Round-robin assignment: block production rights rotate across builders rather than being auctioned. Blind signing: the sequencer sees only the block hash and builder identity, not the contents. Simplicity: the sequencer is designed to be minimal and easy to maintain. Application Controlled Execution (ACE) The ability for applications to read Ethereum state and execute logic on Signet within the same block, with atomic guarantees. ACE enables cross-chain operations without oracles, relayers, or trust assumptions beyond Ethereum itself. Key components: Same-block synchronization: Every Signet block corresponds to exactly one Ethereum block with identical timestamps. L1-driven execution: Passage deposits and Transactor calls from Ethereum execute on Signet in the same block. Conditional execution: Orders on Signet require corresponding Fills on Ethereum to be valid. See Application Controlled Execution for details. OrderDetector An EVM inspector that enforces atomicity for conditional transactions. The OrderDetector validates that every Order has sufficient corresponding Fills before the transaction can commit. How it works: Detects Order and Filled events during transaction execution Uses frame-based tracking to handle nested calls and reverts Validates fills against orders via aggregate comparison Returns an error if any output lacks a sufficient fill If validation fails, the entire transaction reverts—no partial executions, no stranded assets. Passage The contract that handles asset deposits from Ethereum to Signet. When users deposit assets to Passage on Ethereum, Signet observes the deposit event and mints corresponding tokens in the same block. Supported operations: Enter: Deposit native ETH EnterToken: Deposit ERC-20 tokens (USDC, USDT, WBTC, WETH) Passage deposits are censorship-resistant—the protocol enforces their execution. See Passage Documentation and the Passage contract. Transactor The contract that enables arbitrary transaction execution from Ethereum to Signet. Ethereum contracts can call Transactor to trigger Signet execution with native authentication—the Signet transaction executes from the caller's address. Use Transactor when: You need guaranteed transaction inclusion You want to trigger Signet actions from Ethereum You need censorship resistance Transactor events execute at the end of each Signet block and cannot be censored. See Transactor Documentation and the Transactor contract. Zenith The core smart contract system that anchors Signet to Ethereum. Zenith handles block submission, sequencer signatures, and cross-chain coordination. Key contracts in the Zenith system: Zenith.sol: Block submission and sequencer signature verification Passage.sol: Asset bridging from Ethereum to Signet Transactor.sol: L1-driven transaction execution Orders contracts: Cross-chain order matching See the Zenith repository for contract source code. -------------------------------------------------------------------------------- ### No proofs or state roots URL: https://test.signet.sh/docs/learn-about-signet/no-proofs-or-state-roots/ How Signet eliminates proving overhead for better performance -------------------------------------------------------------------------------- # No proofs or state roots Why this matters No proving systems or state roots drastically reduces computational overhead Conditional transactions provide secure, atomic cross-chain operations Cross-chain transfers are market-based Rollups extend Ethereum by allowing nodes to track additional data. Traditional rollups face significant complexity when communicating this data back to Ethereum, typically relying on proving systems. Signet takes a different approach. ## No proving system Most rollups use complex proving systems like optimistic or zero-knowledge proofs to communicate with Ethereum. These systems introduce significant overhead and complexity and are not necessary for most users. Instead of a proving system, Signet facilitates cross-chain transfers through markets. Assets are bought and sold between Signet and Ethereum, rather than being "proven" back onto Ethereum. This approach: * Reduces computational overhead, lowering transaction costs * Increases capacity for processing transactions * Simplifies the overall architecture, making it easier to maintain and upgrade ## No state roots [State roots](/docs/more-info/glossary/#state-roots) were designed for a world where everyone runs a full node. However, most users today interact with blockchains through intermediaries like wallet providers or node services, relying on these for state information rather than verifying the entire chain themselves. In this new paradigm, state roots are much less critical for day-to-day operations and consume significant computational resources. Signet removes state roots as part of our broader strategy to streamline rollup architecture. By eliminating the proving system, we've created an environment where state roots become redundant. This allows us to focus on what matters most to users: fast, cheap transactions and a simple, robust system. By removing state roots, Signet: * Drastically reduces computational overhead * Significantly increases transaction throughput * Lowers transaction costs for users Tradeoffs of this Approach Signet prioritizes the happy path and the average user. While removing proving systems and state roots offers significant benefits to most people, it does not support the following: Light clients Cryptographic proofs of state -------------------------------------------------------------------------------- ### Permissioned roles URL: https://test.signet.sh/docs/more-info/permissioned-roles/ Overview of permissioned roles in Signet smart contracts -------------------------------------------------------------------------------- # Permissioned Roles Signet's smart contracts use a system of permissioned roles to manage access control. Each contract has specific roles that can perform certain administrative functions. ## Core Roles ### Sequencer Admin The `sequencerAdmin` role manages the list of authorized sequencers in the Zenith contract. This role can: - Add or remove sequencers - Update sequencer configuration - Pause sequencing if needed ### Sequencer The `sequencer` role is responsible for validating and co-signing blocks before they are submitted to the Zenith contract. Sequencers: - Validate blocks from builders - Co-sign valid blocks - Ensure blocks follow the protocol rules ### Gas Admin The `gasAdmin` role in the Transactor contract manages gas-related parameters for force-included transactions. This role can: - Update gas price limits - Adjust gas estimation parameters - Configure gas subsidies ### Token Admin The `tokenAdmin` role in the Passage contract manages which tokens can be bridged between chains. This role can: - Add new supported tokens - Update token configuration - Set bridge limits for specific tokens ## Role Management All permissioned roles are managed through a secure access control system. Role transitions are logged on-chain through events. -------------------------------------------------------------------------------- ### Simple sequencing URL: https://test.signet.sh/docs/learn-about-signet/simple-sequencing/ Signet's approach to transaction ordering and inclusion -------------------------------------------------------------------------------- # Simple sequencing Why this matters Ethereum block production is overwhelmingly centralized. Most blocks are built by just a few builders (see below) To address this centralization, Signet assigns block production rights in a round-robin style to block builders This round-robin model does away with proposer-builder auctions and therefore prevents the most wealthy block builders from dominating the market ## Centralization of Sequencing Every blockchain needs a way to order transactions — that's sequencing. Ethereum uses auctions to determine who gets to build blocks and sequence transactions. There are a few problems with this: 1. Auctions mainly benefit the Ethereum block proposer, even though they do no valuable work. 2. Auctions centralize block building by favoring a small number of hyper-specialized builders who can out-compete smaller players. Ethereum's blocks are built by a small number of block builders Block building is a very high-sophistication activity, leading to a very competitive market. Marginal improvements in MEV extraction lead to significantly increased probability of winning a block auction. This means that the most aggressive builders tend to squeeze out smaller builders. This leads to aggregation of control in the hands of a small number of builders. Block builder market share statistics from MEVboost.pics show that Ethereum's blocks are built by just a handful of builders. Even worse, rollup sequencing is centralized _by default._ The chain's order is set by a single entity, with little-to-no recourse. No rollup has credible plans to decentralize the sequencer. ## An alternative approach to sequencing Instead of auctions, Signet uses a central sequencer that _**assigns block production rights**_ to block builders in a round-robin fashion. Each Ethereum block, a specific builder may create a Signet block. That builder is responsible for creating a Signet block and for submitting that block to Ethereum. The Signet sequencer co-signs the builder's block _without seeing its contents_. ### Resistance to censorship by the Signet sequencer Once the assigned builder has produced a block, the Signet sequencer co-signs the block header without seeing the block contents. This means the sequencer only sees the block's hash and the builder's identity, not the transactions. By signing blocks without knowing their contents, the Signet sequencer can't selectively censor transactions, ensuring fair and unbiased block inclusion while maintaining its role in managing builder participation. Tradeoffs of this approach This model represents a trade-off between theoretical and operational decentralization. While Ethereum's system is theoretically decentralized, in that there is no single authority or administrator, it is operationally centralized because a small number of block builders control sequencing. Signet's approach prioritizes operational decentralization by increasing the number of builders, by introducing a centralized sequencer to permission and manage that builder set. We believe that active management is the best solution to emergent centralization. -------------------------------------------------------------------------------- ### Simulating bundles URL: https://test.signet.sh/docs/build-on-signet/advanced/simulating-bundles/ How to simulate Signet bundles before submission using the RPC method. -------------------------------------------------------------------------------- Once you've [created a bundle](/docs/build-on-signet/advanced/bundles/), simulate it against a Signet RPC node before submitting. Simulation lets you verify execution, check profitability, and confirm that order fills are satisfied. The `signet_callBundle` RPC method is Signet's equivalent to Flashbots's [`eth_callBundle`](https://docs.flashbots.net/flashbots-auction/advanced/rpc-endpoint#eth_callbundle). RPC Privacy Simulating bundles leaks their content to the RPC operator. Use an RPC that you trust or control to ensure bundle privacy. -------------------------------------------------------------------------------- ### Swap within Signet URL: https://test.signet.sh/docs/build-on-signet/transfers/swap-within-signet/ Trade tokens on Signet without exiting to Ethereum -------------------------------------------------------------------------------- When you want a different token on Signet without crossing to Ethereum, create an order where both input and output are on the rollup chain. The order stays entirely within Signet and settles without touching Ethereum at all. For order structure, pricing, and filler economics, see the [Exit Signet](/docs/build-on-signet/transfers/exit-signet/) shared intro. The order model is identical -- only the output `chainId` differs. -------------------------------------------------------------------------------- ### System transactions URL: https://test.signet.sh/docs/build-on-signet/system-transactions/ How events on Ethereum produce transactions on Signet, including asset minting and host-originated execution. -------------------------------------------------------------------------------- # System transactions Transactions on Signet can originate from Ethereum. When the Signet node observes specific events from the [Passage](/docs/build-on-signet/transfers/enter-signet/) or [Transactor](/docs/build-on-signet/advanced/execute-from-ethereum/) contracts on the host chain, it creates corresponding transactions on the rollup. Three host-chain event types produce system transactions: | Event | Trigger | | ------------- | -------------------------------------------- | | `Enter` | ETH deposited to Passage | | `EnterToken` | ERC-20 tokens deposited to Passage | | `Transact` | Arbitrary execution requested via Transactor | System transactions execute **last** in the block, after all user-submitted transactions. Processing order within that group is: 1. `Enter` 2. `EnterToken` 3. `Transact` A single host transaction can produce multiple system transactions. For example, the Transactor's `enterTransact` function emits both an `Enter` event and a `Transact` event, producing two system transactions in the same block. ## MagicSig System transactions are not signed by a private key. The signature field carries a **MagicSig** with three fields: - **Event type**: `Enter`, `EnterToken`, or `Transact` - **Transaction hash**: the host-chain transaction that emitted the event - **Event index**: position of the event within the transaction's logs The `s` value of the signature begins with the sentinel `0xffeeddcc`, which exceeds the secp256k1 curve order. This makes it impossible to confuse a MagicSig with a real ECDSA signature on any EIP-2 chain. For `Transact` events, the MagicSig also encodes the sender address and whether [address aliasing](/docs/learn-about-signet/evm-behavior/#address-aliasing) was applied. See the [MagicSig documentation](https://docs.rs/signet-types/latest/signet_types/struct.MagicSig.html) for the full wire format specification. ## Native asset mints When USDC or USDT is deposited through Passage (`EnterToken` event), the node mints native [USD](/docs/learn-about-signet/evm-behavior/#usd-native-asset) directly to the recipient's balance. This is not an EVM transaction. The node increases the account balance directly, without executing contract code. Amounts are normalized from the host token's decimals to 18. For example, 1 USDC (`10**6` on Ethereum) becomes `10**18` wei of native USD on Signet. The node emits a `MintNative` system log from `MINTER_ADDRESS`: ```solidity event MintNative( bytes32 indexed txHash, uint64 indexed logIndex, address indexed recipient, uint256 amount ); ``` `MINTER_ADDRESS` is `0x00000000000000000000746f6b656e61646d696e`. ## Token mints ETH deposits (`Enter`) and non-USD token deposits (`EnterToken`) produce a token mint transaction. The node calls `mint(recipient, amount)` on the corresponding rollup-side ERC-20 contract. | Host asset | Rollup token | | ---------- | ------------ | | ETH | WETH | | WBTC | WBTC | These transactions run from `MINTER_ADDRESS` with zero gas cost. **Transaction properties:** - `from`: `MINTER_ADDRESS` - `to`: the rollup token contract - `value`: 0 - `nonce`: next nonce for `MINTER_ADDRESS` - `input`: ABI-encoded `mint(address recipient, uint256 amount)` - `max_fee_per_gas`: 0 - `max_priority_fee_per_gas`: 0 The node emits a `MintToken` system log from `MINTER_ADDRESS`: ```solidity event MintToken( bytes32 indexed txHash, uint64 indexed logIndex, address indexed recipient, address hostToken, uint256 amount ); ``` ## Transact When the host [Transactor](/docs/build-on-signet/advanced/execute-from-ethereum/) emits a `Transact` event, the node creates a transaction on Signet from the caller's address. This allows Ethereum contracts to own assets on Signet and trigger execution there, using their Ethereum address as the sender. **Transaction properties:** - `from`: the host-chain `msg.sender`, [aliased](/docs/learn-about-signet/evm-behavior/#address-aliasing) if the sender is a smart contract - `to`: as specified in the event - `value`: as specified in the event (USD wei) - `input`: as specified in the event - `nonce`: next nonce for the sender's Signet account - `gas_limit`: as specified in the event - `max_fee_per_gas`: as specified in the event - `max_priority_fee_per_gas`: 0 Inclusion guarantee If the Transact event was emitted on the host chain, the system transaction is guaranteed to be included on Signet. Inclusion does not guarantee the inner call succeeds. Contract creation via Transactor is not supported. -------------------------------------------------------------------------------- ### Cross-chain transfers URL: https://test.signet.sh/docs/learn-about-signet/cross-chain-transfers/ How assets move seamlessly between chains -------------------------------------------------------------------------------- # Cross-chain transfers Why this matters Moving assets into and out of Signet is simple and instant Conditional transactions require cross-chain transfers to be fully executed in the same block on both chains ## Moving from Ethereum to Signet Because Signet produces blocks at the same time as Ethereum, assets and data can move freely from Ethereum to Signet in the same block. If you send Ether to Signet, entering Signet has **no time delay**. Signet does not require a multi-minute wait like centrally sequenced rollups. Users can also send transactions from Ethereum to Signet. These transactions correspond to the "forced inclusion" mechanisms on other rollups but have **no time delay.** They always execute immediately on Signet, at the end of the current block. Moving from Ethereum to Signet always occurs in the same block, and cannot be censored or delayed by anyone. At present, Signet supports ETH, USDC, USDT, and WBTC. Custom assets may be created within Signet, but not bridged from Ethereum. If you would like your asset to be bridged to Signet from Ethereum, please reach out. Example: Moving assets from Ethereum to Signet The Passage contract facilitates asset transfers from Ethereum to Signet. A user wants to move 10 ETH from Ethereum to Signet: User sends 10 ETH to the Passage contract on Ethereum. The contract emits an Enter event. Signet Rollup Node observes the event. Rollup Node credits 10 WETH (an ERC-20) to the user's address on Signet. This process is permissionless and requires no action on Signet from the user. ## Moving from Signet to Ethereum Signet introduces [Conditional Transactions](/docs/more-info/glossary/#conditional-transactions) to enable both local trades, and cross-chain transfers. Conditional transactions succeed _if and only if_ some condition is met at the end of execution. This condition can look at state within the rollup, or in limited cases on Ethereum. This allows same-block interaction and trading with Ethereum. Transfers and trades are conditional on full execution. I.e. if the trade does not complete, it never occurs at all. The rollup erases failed trades and failed transfers from its history. Signet requires cross-chain transfers to be fully executed in the same block on both chains. Otherwise, the transaction is invalid and has no effect on Signet's state; it's as if the transaction never existed. This allows for secure, instant transfers between Ethereum and Signet, so long as there is a Filler willing to accept the user's order. No Lockup Period Existing rollups introduce lockup periods for user withdrawals. With Signet, there is no lockup period for market-based transfers, allowing instant settlement. Example: Moving assets from Signet to Ethereum A user wants to move 5 ETH from Signet to Ethereum. They create a conditional transaction to transfer 5 ETH. This transaction is only valid if the user receives 5 ETH on Ethereum in the same block. Some Filler accepts this order by sending 5 ETH to the user on Ethereum. The conditional transaction is now valid. The Filler receives 5 ETH on Signet. The user's ETH on Signet moves if and only if the ETH on Ethereum goes to the user. The user cannot lose their ETH, unless they also get ETH. Tradeoffs of this approach Signet prioritizes the happy path and the average user. Conditional transactions provide same-block trades and interactions with Ethereum, however, they cannot provide the following: Synchronous composability Arbitrary message passing between smart contracts -------------------------------------------------------------------------------- ### Troubleshooting URL: https://test.signet.sh/docs/build-on-signet/advanced/troubleshooting/ Common errors, how to handle them, and debugging tips for Signet development. -------------------------------------------------------------------------------- Common errors and debugging tips for Signet development. Select your language to see relevant code. -------------------------------------------------------------------------------- ### Key concepts URL: https://test.signet.sh/docs/learn-about-signet/key-concepts/ The building blocks you'll use when developing on Signet. -------------------------------------------------------------------------------- # Key concepts Signet is an EVM rollup that settles on Ethereum. Your application interacts with two chains simultaneously: Signet (the rollup) and Ethereum (the host chain). Deposits, swaps, and fills happen across both in the same block. ## The building blocks **[Passage](/docs/learn-about-signet/cross-chain-transfers/)** moves assets from Ethereum into Signet. Deposits arrive in the same block. **[Orders](/docs/learn-about-signet/how-orders-work/)** move assets from Signet back to Ethereum (or any chain). A filler delivers the output, and atomic settlement ensures both sides execute or neither does. **[The transaction cache](/docs/learn-about-signet/how-orders-work/#the-transaction-cache)** is how you submit transactions, signed orders, and bundles to Signet's sequencer infrastructure. **[The Transactor](/docs/build-on-signet/advanced/execute-from-ethereum/)** triggers execution on Signet from Ethereum with guaranteed, censorship-resistant inclusion. ## Synchronized settlement Signet produces blocks synchronized with Ethereum. When your user deposits ETH via Passage on Ethereum, the tokens appear on Signet in the same block. When they create an order to exit, a filler delivers on Ethereum and the builder settles both sides atomically. ## Parmigiana testnet [Parmigiana](/docs/build-on-signet/parmigiana/) is Signet's public testnet. It has a faucet for test tokens, RPC endpoints, and all deployed contract addresses. Use it for development and testing. ## Next steps Start with the [getting started guide](/docs/build-on-signet/getting-started/) to set up your development environment. -------------------------------------------------------------------------------- ### Application controlled execution URL: https://test.signet.sh/docs/learn-about-signet/application-controlled-execution/ How applications coordinate atomic cross-chain execution between Signet and Ethereum -------------------------------------------------------------------------------- # Application controlled execution Why this matters Applications can read Ethereum state and react on Signet in the same block Cross-chain operations execute atomically or not at all No oracles, relayers, or trust assumptions beyond Ethereum itself ## Same-Block Synchronization Signet produces blocks in lockstep with Ethereum. Every Signet block corresponds to exactly one Ethereum block, with identical timestamps. This 1:1 coupling enables Signet to observe Ethereum state as it happens—not minutes later through an oracle, but in the same 12-second window. This synchronization is the foundation of Application Controlled Execution (ACE). Applications can react to Ethereum events and execute logic on Signet within the same block, with atomic guarantees. ## L1-Driven Execution Two primitives allow Ethereum to drive execution on Signet: **Enter/EnterToken** — The [Passage](/docs/build-on-signet/transfers/enter-signet/) contract handles asset deposits. When users deposit to Passage on Ethereum, Signet observes the event and mints corresponding tokens in the same block. No relayer, no delay. **Transact** — The [Transactor](/docs/build-on-signet/advanced/execute-from-ethereum/) contract enables arbitrary transaction execution. Ethereum contracts can trigger Signet execution with native authentication—the Signet transaction executes from the caller's address. Both mechanisms are censorship-resistant. The protocol enforces their execution; no sequencer or builder can exclude them. If the Ethereum transaction is included, the Signet action executes. Example: L1-driven contract execution An Ethereum contract needs to trigger an emergency pause on Signet: Contract calls Transactor.transact() with the pause function calldata. The Transactor emits a Transact event on Ethereum. Signet node observes the event in the same block. The pause transaction executes on Signet at block end. The Signet execution cannot be censored or delayed. ## Conditional Execution The reverse direction—Signet to Ethereum—uses conditional transactions through the [Orders](/docs/build-on-signet/transfers/exit-signet/) system. A conditional transaction emits an Order specifying required outputs. The transaction is valid if and only if all outputs have corresponding Fills on Ethereum in the same block: - **Fills exist**: Transaction executes on both chains - **Fills missing**: Transaction reverts entirely, as if it never happened The OrderDetector validates this atomicity at the protocol level. It checks that every Order has sufficient Fills before the transaction can commit. No partial executions, no stranded assets. Example: Instant exit from Signet A user wants to move 1 ETH from Signet to Ethereum instantly: User creates an Order: "Send 1 ETH on Signet, receive 1 ETH on Ethereum." A Filler sees this order and sends 1 ETH to the user on Ethereum. The OrderDetector confirms the Fill exists. The user's Signet ETH transfers to the Filler. Both sides execute atomically. The user cannot lose their Signet ETH without receiving Ethereum ETH. ## The Filler Market Fillers are MEV searchers who compete to fulfill Orders. They provide the output tokens on Ethereum and receive the input tokens on Signet. Competition between Fillers drives efficient pricing—users get market rates for their cross-chain transfers. This market-based approach replaces the lockup periods of traditional rollup withdrawals. Instead of waiting days for finality, users pay a filler fee (50 basis points or less) for instant settlement. See [The Filler Economy](/updates/the-filler-economy/) for a deeper exploration of how Fillers operate. ## Building with ACE The [Signet SDK](https://github.com/init4tech/signet-sdk) provides Rust primitives for building applications with controlled execution. For Solidity patterns, see the [On-chain Orders](/docs/build-on-signet/transfers/exit-signet/#solidity) documentation. Common patterns include: - **Flash loans** — Borrow on Signet, use on Ethereum, repay atomically - **Instant exits** — Market-priced withdrawal with no lockup period - **Payment gating** — Require L1 payment before Signet execution - **Execution bounties** — Incentivize specific L1 actions Need something more specialized? If your use case requires general-purpose message passing, mid-execution L1 calls with return values, or other cross-chain patterns, Signet's primitives often support these workflows in ways that aren't immediately obvious. Get in touch to discuss. ## Custom Implementations Have a specific cross-chain use case? We build custom ACE implementations for application developers -- custom order types, fill strategies, or cross-chain workflows. [Get in touch](https://t.me/anthspezzano) to discuss your requirements. -------------------------------------------------------------------------------- ### Brand kit URL: https://test.signet.sh/docs/more-info/brand-kit/ Visual identity essentials for Signet -------------------------------------------------------------------------------- # Brand Kit ## Logo Use the mark alongside the wordmark "Signet" set in New York. Signet Signet ### Usage Guidelines - Maintain clear space equal to the mark's height on all sides - Never distort, rotate, or add effects to the mark - On light backgrounds, use ink (#2D2926) - On dark backgrounds, use cream (#FAF7F2) ## Color Palette ### The Six Inks 金 Kin Gold Accent, Keywords #D4A929 松 Matsu Pine Success, Strings #5B8A5B 朱 Shu Vermillion Danger, Errors #B85450 月 Tsuki Moon Info, Functions #4A8090 藤 Fuji Wisteria Secondary, Types #7868A0 桜 Sakura Blossoms Special, Escapes #C0707A ### Paper Tones Cream #FAF7F2 Warm #F5F1EA Rule #E3DED5 Mist #ADA69C Stone #7C756C Graphite #4A4541 Ink #2D2926 ## Typography Display New York Headlines, page titles, feature text Body Iowan Old Style Long-form content, paragraphs, prose Mono SF Mono Code, labels, technical content ### Scale | Token | Size | Usage | |-------|------|-------| | micro | 10px | Labels, eyebrows, badges | | caption | 12px | Captions, metadata | | small | 13px | Secondary text, buttons | | body | 15px | Body copy | | h4 | 16px | Minor headings | | h3 | 18px | Subsections | | h2 | 22px | Sections | | h1 | 28px | Page titles | ## Components Buttons Badges Kin Matsu Shu Tsuki Fuji Sakura Default Callouts Note Informational callout for helpful context. Warning Warning callout for important cautions. Table Name Type Status Order #1234 Transfer Confirmed Order #1235 Swap Pending Collapsible Click to expand Hidden content revealed on click. Use for FAQs, optional details, or progressive disclosure. Form Inputs Checkbox Unchecked Option A Option B -------------------------------------------------------------------------------- ### How orders work URL: https://test.signet.sh/docs/learn-about-signet/how-orders-work/ The cross-chain order system that powers exits, swaps, and settlement on Signet -------------------------------------------------------------------------------- # How orders work An Order is Signet's primitive for moving assets between chains. The user specifies what they're giving up on Signet and what they want to receive on another chain. A filler delivers the output, a builder settles both sides atomically, and either the entire trade executes or nothing happens. Orders power exits, swaps, and any cross-chain transfer that requires atomic settlement. ## The lifecycle 1. **The user creates an Order.** They give up tokens on Signet and specify what they want on Ethereum (or any supported chain). 2. **The Order is submitted to the [transaction cache](#the-transaction-cache).** On-chain orders are discovered via events; gasless orders are posted directly by your application. 3. **Fillers evaluate the Order.** They assess the spread between input and output and decide if the trade is profitable. 4. **A filler commits.** They construct a fill transaction for the destination chain and bundle it with the Signet-side settlement. A builder includes the bundle in a block proposal. 5. **Atomic settlement.** Either both sides execute or neither does. The builder enforces atomicity. If the filler doesn't deliver on the destination chain, the user's tokens are never taken on Signet. There is no window where funds are at risk. This is powered by [conditional transactions](/docs/learn-about-signet/cross-chain-transfers/#moving-from-signet-to-ethereum): operations that only execute if both sides complete in the same block. ## What goes into an order Every Order has two parts: what the user gives up (inputs) and what they receive (outputs). An input is a token and amount on Signet. An output is a token, amount, recipient, and destination chain. Orders can have multiple inputs and outputs across different chains. The spread between input and output is the filler's incentive -- it's how the market prices the service of delivering tokens on the destination chain. ## The transaction cache The transaction cache (tx-cache) is Signet's submission service. Transactions, signed orders, and bundles go here before inclusion in blocks. Gasless orders are submitted to the tx-cache, where fillers discover and evaluate them. On-chain orders skip the tx-cache entirely since they're created directly on Signet. The Parmigiana testnet endpoint is `https://transactions.parmigiana.signet.sh`. ## Next steps - [Exit Signet](/docs/build-on-signet/transfers/exit-signet/): build exit orders in your language - [Swap within Signet](/docs/build-on-signet/transfers/swap-within-signet/): trade tokens without leaving the rollup -------------------------------------------------------------------------------- ### EVM behavior URL: https://test.signet.sh/docs/learn-about-signet/evm-behavior/ EVM modifications and differences between Signet and Mainnet EVM. -------------------------------------------------------------------------------- # EVM behavior Signet targets full EVM compatibility. This page describes the (very few) differences between Signet and Ethereum Mainnet EVM behavior. ## USD Native Asset The native asset on Signet is USD, not ETH. USD plays the same role that ETH does on Ethereum: it pays for gas, it's what `msg.value` transfers, and it's what `address.balance` returns. It has 18 decimals. USD is minted on Signet when USDC or USDT is deposited through [Passage](/docs/build-on-signet/transfers/enter-signet/). The node observes the deposit event on Ethereum and credits the recipient's balance with native USD, normalizing decimals from 6 to 18. ETH and other supported tokens (WBTC) are bridged as ERC-20 tokens, not native USD. See [System transactions](/docs/build-on-signet/system-transactions/) for details on how deposits are processed. WUSD is the wrapped ERC-20 version of USD, the same relationship as WETH to ETH on Ethereum. Use WUSD when a contract or protocol requires an ERC-20 rather than the native asset. The SDK refers to the native asset as `USD` and the wrapped token as `WUSD`. ## Inherited header values The following opcodes inherit the values of the Ethereum block: - `PREVRANDAO`: `block.difficulty` and `block.prevrandao` - `TIMESTAMP`: `block.timestamp` Signet blocks always use the same timestamp as the current Ethereum block. ## Disabled Opcodes The following opcodes are disabled in Signet: - `BLOBHASH`: EIP-4844 is not supported. - `BLOBBASEFEE`: EIP-4844 is not supported. ## Precompiles Signet supports the [same precompiles as ethereum], plus the following additional precompile: - secp256r1 signature verification as specified in [RIP-7212] at address `0x100`. ## Address Aliasing To conform to common rollup conventions, Signet uses address aliasing for L1-to-L2 messages. When a contract on L1 sends a message to Signet via the [`Transactor`] contract, the sender's address is modified by adding a constant offset to it. This ensures that contracts on Signet can distinguish between messages sent from L1 and those sent from the same address on the L2. The address aliasing offset is `0x1111000000000000000000000000000000001111`. Aliasing is performed by converting the address to a number, adding the offset, and then converting back to an address. Signet differs from other rollup behaviors in that the addresses of ephemeral contracts are NOT aliased. Signet treats ephemeral L1 contracts equivalently to EOAs. | Account Type | Address Aliased? | | ------------------- | ---------------- | | EOA | No | | EIP-7702 Delegation | No | | Ephemeral Contract | **No** | | Smart Contract | Yes | [same precompiles as ethereum]: https://www.evm.codes/precompiled [RIP-7212]: https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md [`Transactor`]: /docs/build-on-signet/advanced/execute-from-ethereum/ -------------------------------------------------------------------------------- ### Clone and build URL: https://test.signet.sh/docs/block-builders/run-a-builder/clone-and-build/ Prerequisites, system requirements, and instructions for cloning and building the Signet builder. -------------------------------------------------------------------------------- # Clone and Build the Signet Builder The Builder simulates bundles and transactions to create valid rollup blocks and submits them to Ethereum. ## Prerequisites - **Rust** ≥ 1.85 - **Git** - **AWS CLI** ## Recommended System Specs - CPU: 0.5 vCPU (minimum 0.1 vCPU) - Memory: 512MB (minimum 256MB) - Clock speed: 2.8GHz+ (builder prefers clock speed over core count) ## Clone the Repository ```bash git clone https://github.com/init4tech/builder cd builder ``` ## Build Options ### Local Build ```bash cargo build --release ``` The compiled binary will be available at `target/release/builder`. ### Docker Build ```bash docker build -t builder:latest . ``` ## Deployment After building the Docker image: 1. Push to your container registry: ```bash docker push /builder:latest ``` 2. Update your deployment manifests with the new image 3. Verify expected behavior in your target network ## Next Steps - [Configure authentication](/docs/block-builders/run-a-builder/authentication/) to connect to the sequencer - [Configure environment variables](/docs/block-builders/run-a-builder/environment-variables/) for your deployment - [Install and run a node](/docs/block-builders/run-a-builder/install-and-run-a-node/) (optional infrastructure) -------------------------------------------------------------------------------- ### Introduction URL: https://test.signet.sh/docs/block-builders/introduction/ Overview of Signet block building, including key features, quickstart steps, and documentation structure. -------------------------------------------------------------------------------- # Introduction Welcome to Signet's Block Builder Docs. This documentation will help you understand how to build blocks, capture value, and participate in our unique ecosystem. For more general information about Signet, see our public docs. ## Key Features for Builders As a Signet Block Builder, you construct blocks by selecting transactions and bundles, then submit those blocks to Ethereum. * **Direct Sequencer Access**: Work directly with the Signet sequencer in a round-robin slot system, unlike traditional PBS auctions. * **Capture MEV and Sequencer Fees**: Directly extract value from transactions within your blocks. * **Fair Block Production**: Round-robin sequencing ensures equitable opportunities for all builders. ## Quickstart To get started as a block builder: 1. **[Clone and build](/docs/block-builders/run-a-builder/clone-and-build/)** the Signet builder repository 2. **[Set up authentication](/docs/block-builders/run-a-builder/authentication/)** to connect to the sequencer 3. **[Install and run a node](/docs/block-builders/run-a-builder/install-and-run-a-node/)** to start building blocks ## Documentation Structure This documentation is organized to get you building quickly: ### Running a Builder Everything you need to get a builder up and running: - **[Clone and Build](/docs/block-builders/run-a-builder/clone-and-build/)**: Get the Signet builder source code and compile it - **[Authentication](/docs/block-builders/run-a-builder/authentication/)**: Configure OAuth credentials for sequencer access - **[Install and Run a Node](/docs/block-builders/run-a-builder/install-and-run-a-node/)**: Deploy and operate your builder node - **[Environment Variables](/docs/block-builders/run-a-builder/environment-variables/)**: Configure your builder for different networks ### Customizing a Builder Advanced topics for customizing block construction: - **[Getting Transactions and Bundles](/docs/block-builders/customizing-a-builder/getting-transactions-and-bundles-for-a-block/)**: Access the transaction pool and bundle relay - **[Getting a Sequencer Signature](/docs/block-builders/customizing-a-builder/getting-a-sequencer-signature/)**: Obtain co-signatures for your blocks - **[Bundle Guarantees](/docs/block-builders/customizing-a-builder/bundle-guarantees/)**: Understand bundle execution guarantees - **[Submitting Blocks](/docs/block-builders/customizing-a-builder/submitting-a-block-to-ethereum/)**: Submit your blocks to Ethereum via EIP-4844 ## Next Steps Start with [Clone and Build](/docs/block-builders/run-a-builder/clone-and-build/) to get your builder environment set up. ================================================================================ ## Recent Updates -------------------------------------------------------------------------------- ### Building with Orders URL: https://test.signet.sh/updates/building-with-orders/ A practical guide to placing and filling cross-chain orders on Signet Published: 2025-08-20 -------------------------------------------------------------------------------- This guide walks through implementing cross-chain orders on Signet. By the end, you'll have working code for both sides of the order flow: creating orders as an application, and filling orders as a market participant. **What you'll build:** - Order creation: Express user intent through signed Permit2 structures - Order filling: Compete to fulfill orders profitably - Bundle coordination: Atomic execution across chains **Prerequisites:** - Rust development environment - Funded wallet on [Parmigiana testnet](/docs/build-on-signet/parmigiana/) - Familiarity with [The Filler Economy](/updates/the-filler-economy/) concepts All code is available in [`signet-orders`](https://github.com/init4tech/signet-orders). --- ## Part 1: Creating Orders Orders express cross-chain intent. A user says: "I'll give you X on Signet if you give me Y on Ethereum." Applications construct and sign these orders on behalf of users. ### The SendOrder Pattern **Code: [`src/order.rs`](https://github.com/init4tech/signet-orders/blob/main/src/order.rs)** ```rust impl SendOrder { /// Sign an order and submit it to the transaction cache pub async fn sign_and_send_order(&self, order: Order) -> Result<()> { let signed = self.sign_order(order).await?; self.send_order(signed).await } /// Sign an order without submitting pub async fn sign_order(&self, order: Order) -> Result { // Build Permit2 authorization and sign // ... } /// Submit a pre-signed order to the transaction cache pub async fn send_order(&self, signed: SignedOrder) -> Result<()> { self.tx_cache.forward_order(signed).await } } ``` **What's happening:** 1. **Order construction**: Build the order specifying inputs (what user gives) and outputs (what user wants) 2. **Permit2 signing**: User approves token spend with a single signature (no separate approve tx) 3. **Submission**: Order goes to the transaction cache where Fillers discover it ### Order Structure ```rust pub struct SignedOrder { pub permit: Permit2Batch, // Single signature authorization pub outputs: Vec, // What user wants to receive } pub struct Output { pub token: Address, // Asset (e.g., WETH) pub amount: Uint<256, 4>, // Amount pub recipient: Address, // Where to send it pub chainId: u32, // Which chain (1 = Ethereum) } ``` Orders have a ~10 minute validity window. If no Filler accepts within that window, the order expires and nothing happens. --- ## Part 2: Filling Orders Fillers are market participants who fulfill orders for profit. They provide the outputs users want and receive the inputs users offer. ### The Filler Pattern **Code: [`src/filler.rs`](https://github.com/init4tech/signet-orders/blob/main/src/filler.rs)** ```rust impl Filler { pub async fn fill(&self, orders: Vec) -> Result<()> { // 1. Construct and sign Permit2 fills for destination chains let fills = self.construct_fills(&orders).await?; // 2. Build atomic bundle combining initiates and fills let bundle = self.build_signet_bundle(&orders, &fills).await?; // 3. Submit to Transaction Cache for builder inclusion self.tx_cache.submit_bundle(bundle).await } } ``` **What's happening:** 1. **Construct fills**: Filler signs their side of the trade (providing outputs to user) 2. **Build bundle**: Combine order execution with fill execution 3. **Submit**: Bundle goes to builders for atomic inclusion ### Two Filling Strategies **Aggregate execution** — All orders in one bundle: ```rust pub async fn fill(&self, orders: Vec) -> Result<()> { // Submit all Orders/Fills in single Bundle // Atomic: all succeed or none do } ``` Pros: Gas efficient, can reuse capital across orders Cons: Single failure breaks entire bundle **Individual execution** — Each order in its own bundle: ```rust pub async fn fill_individually(&self, orders: Vec) -> Result<()> { // Submit each Order/Fill in separate Bundle // Independent: orders succeed or fail separately } ``` Pros: Resilient, simple validation Cons: Higher gas, can't optimize across orders Choose based on your risk tolerance and order flow. --- ## Part 3: Bundle Construction Orders and fills execute atomically through Signet's bundle system. ```rust let bundle = SignetEthBundle { host_fills: Some(permit2_fills), // Ethereum-side actions bundle: EthSendBundle { txs: signet_transactions, // Signet-side transactions block_number: target_block, reverting_tx_hashes: vec![], // No partial execution } }; ``` **Key properties:** - **Block-specific**: Bundles target a specific block number - **Atomic**: All transactions succeed or none do - **Retry-able**: Failed bundles can target the next block The `OrderDetector` in Signet's EVM enforces atomicity: order transactions only execute if corresponding fills exist. --- ## Part 4: Running the Example The [`roundtrip`](https://github.com/init4tech/signet-orders/blob/main/bin/roundtrip.rs) example demonstrates the complete flow. ### Setup **1. Configure environment:** ```bash export CHAIN_NAME=parmigiana export RU_RPC_URL=https://rpc.parmigiana.signet.sh/ export SIGNER_KEY=[your private key or AWS KMS key ID] export SIGNER_CHAIN_ID=88888 ``` **2. Fund your wallet:** Your signing key needs: - Input tokens (what you're swapping from) - Output tokens (what you're providing to users) - Gas: ETH on Ethereum, USD on Signet **3. Approve Permit2:** ```bash cast send [TOKEN_ADDRESS] "approve(address,uint256)" \ 0x000000000022D473030F116dDEE9F6B43aC78BA3 \ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \ --rpc-url $RPC_URL ``` Permit2 uses the same address on Parmigiana and Ethereum mainnet. ### Run **Rollup → Host swap:** ```bash cargo run --bin order-roundtrip-example ``` **Rollup → Rollup swap:** ```bash cargo run --bin order-roundtrip-example -- --rollup ``` The example supports both AWS KMS and local private keys. --- ## Production Considerations When building production systems: **Profitability analysis**: Calculate spreads accounting for gas costs, inventory costs, and competition. **Key management**: Use AWS KMS, HashiCorp Vault, or hardware security modules. Never use raw private keys in production. **Monitoring**: Track fill rates, win rates against competitors, and inventory levels. **Error handling**: Implement retry logic for network failures. Bundles can target subsequent blocks if the first attempt fails. **Gas optimization**: Choose aggregate vs individual filling based on your order patterns. High-volume, correlated orders benefit from aggregation. --- ## Integration Patterns **Cross-chain DeFi**: Let users open positions on Ethereum using Signet collateral—instantly. **Payment routing**: Route payments to the cheapest chain based on current liquidity. **Arbitrage**: Capture price differences while providing useful execution to users. **Wallet interfaces**: Offer "swap to any chain" without users understanding the mechanics. --- ## Resources **Code:** - [`signet-orders`](https://github.com/init4tech/signet-orders) — Complete examples - [`signet-sdk`](https://github.com/init4tech/signet-sdk) — Core types and utilities **Infrastructure:** - [Parmigiana Faucet](/docs/build-on-signet/parmigiana/) — Fund your dev keys - [Parmigiana Explorer](https://explorer.parmigiana.signet.sh/) — Monitor execution **Concepts:** - [The Filler Economy](/updates/the-filler-economy/) — How markets work - [Application Controlled Execution](/updates/application-controlled-execution/) — What apps can do Questions? [Get in touch](https://t.me/anthspezzano). -------------------------------------------------------------------------------- ### The Filler Economy URL: https://test.signet.sh/updates/the-filler-economy/ How Signet turns MEV extractors into service providers Published: 2025-06-04 -------------------------------------------------------------------------------- MEV is extractive. Searchers front-run your trades, sandwich your swaps, and capture value that should be yours. The Ethereum community has spent years building infrastructure to mitigate MEV—Flashbots, MEV-Share, order flow auctions—all attempting to return some extracted value to users. The same actors who extract value on Ethereum provide value on Signet. Signet's settlement system turns searchers into **Fillers**—market participants who compete to give users better execution, not worse. They're not extracting from your order; they're fulfilling it. The incentives flip. ## The Seven-Day Exit On most rollups, moving assets back to Ethereum means locking them, waiting through a 7-day fraud proof window (or proof generation for zk rollups), and finally claiming on L1. Your capital sits idle for days. Professional market makers won't deploy capital that can't move. Users avoid withdrawals entirely, fragmenting liquidity across chains. A 7-day delay is a 2% annual drag on capital at 10% APY alternatives. For a market maker with $10M deployed, that's $200K/year in opportunity cost. ## Markets, Not Queues Signet replaces withdrawal queues with markets. Instead of waiting for proofs, users create **Orders**—signed intents that say "I'll give you X on Signet if you give me Y on Ethereum." Fillers compete to fulfill these orders. The best price wins. Settlement happens in the same block. ![settlement-mechanics.png](settlement-mechanics.png) ### How It Works **1. User creates an Order** Orders express atomic intent through [Permit2](https://docs.uniswap.org/contracts/permit2/overview): ```rust pub struct SignedOrder { pub permit: Permit2Batch, // Single signature authorization pub outputs: Vec, // What user wants to receive } pub struct Output { pub token: Address, // Asset (e.g., WETH) pub amount: Uint<256, 4>, // Amount (e.g., 1 ETH) pub recipient: Address, // Where to send it pub chainId: u32, // Which chain (1 = Ethereum) } ``` **2. Fillers compete** Orders broadcast to the transaction cache. Multiple Fillers evaluate simultaneously: - Can I fill this profitably? - Do I have inventory on the destination chain? - Can I beat competing Fillers? **3. Winner fills atomically** The winning Filler constructs a bundle: their fill transaction on Ethereum, the user's order transaction on Signet. Both execute in the same block—or neither does. ### The OrderDetector Atomicity is enforced by the `OrderDetector`—an EVM inspector that validates every Order has corresponding Fills before allowing execution. Conceptually: 1. Fills execute first, crediting outputs to recipients 2. Orders execute, debiting inputs from users 3. The detector validates: for each output in the Order, does a sufficient Fill exist? 4. If any Fill is missing, the entire Order reverts Fill transactions must execute before Order transactions. If any Fill is missing, the entire Order is rejected. No partial executions. No stranded assets. ## Extraction vs. Service Traditional MEV is a zero-sum game: searchers profit by taking from users. Signet's Filler economy is positive-sum: Fillers profit by providing a service users want. The difference is **who initiates**: - **MEV**: Searcher observes user's pending transaction, constructs attack - **Filler**: User broadcasts intent, Fillers compete to fulfill it Users set the terms. Fillers compete on price. The best offer wins. If no Filler accepts your order, it doesn't execute — market liveness replaces proof liveness, and you can't force-withdraw without a counterparty. Different from proof-based systems, not necessarily worse. ![price-discovery.png](price-discovery.png) Multiple Fillers evaluate each order simultaneously. Competition drives spreads toward equilibrium, with price discovery occurring every 12 seconds. No single Filler controls market pricing — capital availability determines fill rates, and in a competitive market, spreads approach the cost of capital plus operational overhead. ## Capital That Moves Capital that settles in 12 seconds can be redeployed in the next block. Capital locked for 7 days sits idle. ![capital-velocity.png](capital-velocity.png) Same-block settlement makes strategies practical that don't work with async finality. Fillers can execute multiple trades within a single block and compound returns through circular trading paths. They can optimize cross-chain balances in real time, provision liquidity just-in-time, and net positions across multiple orders in the same block to reduce transaction costs. None of this is possible when capital is locked in a withdrawal queue. ## Building a Filler Fillers implement custom market-making strategies. Here's the pattern (see [signet-orders](https://github.com/init4tech/signet-orders) for a complete implementation): ```rust // Example strategy pattern — implement your own evaluation logic struct MyFiller { min_margin: f64, inventory: InventoryManager, } impl MyFiller { async fn evaluate_order(&self, order: &SignedOrder) -> bool { // Calculate potential profit let profit_margin = self.calculate_margin(order); // Check inventory on destination chain let has_liquidity = self.inventory.has_sufficient(order).await; // Decide whether to fill profit_margin > self.min_margin && has_liquidity } } ``` ### Bundle Construction Fillers aggregate orders into atomic bundles: ```rust async fn construct_bundle(&self, orders: &[SignedOrder]) -> Result { let aggregated = self.aggregate_by_chain(orders); let signed_fills = self.sign_fills(&aggregated).await?; let txs = self.sequence_transactions(&signed_fills, orders).await?; let host_fills = signed_fills.get(ÐEREUM_CHAIN_ID); Ok(SignetEthBundle { host_fills, bundle: EthSendBundle { txs, block_number: self.target_block(), reverting_tx_hashes: vec![], }, }) } ``` Error handling is atomic: - Invalid signatures → Bundle rejected pre-execution - Insufficient liquidity → Fill transaction reverts, Order rejected - Gas exhaustion → Entire bundle fails ## Settlement as Infrastructure Signet embeds market mechanics at the protocol level. ![protocol-level-markets.png](protocol-level-markets.png) Every application built on Signet inherits instant cross-chain settlement. No integration required—it's how the chain works. ## Get Started **For Fillers:** - [Signet SDK](https://github.com/init4tech/signet-sdk): Complete implementation patterns - [Bundle simulation](https://github.com/init4tech/signet-sdk/tree/main/crates/sim): Pre-execution validation **For Builders:** - [Orders documentation](/docs/build-on-signet/transfers/exit-signet/): How orders work - [SDK types](https://github.com/init4tech/signet-sdk/tree/main/crates/types): Type-safe order handling Questions? [Get in touch](https://t.me/anthspezzano). -------------------------------------------------------------------------------- ### How Signet Works URL: https://test.signet.sh/updates/how-signet-works/ The three pieces that make cross-chain execution feel like one chain Published: 2025-04-30 -------------------------------------------------------------------------------- Cross-chain is usually complicated. Bridges, relayers, waiting periods, partial failures. Signet makes it simple: transactions either complete on both chains in the same block, or they don't happen at all. Three mechanisms make this work. ## 1. Synchronized Blocks Every Signet block corresponds to exactly one Ethereum block. Same timestamp. Same finality. If Ethereum reorgs, Signet reorgs. If Ethereum finalizes, Signet finalizes. No pre-confirmations. No optimistic settlement. No challenge period. > **Deep dive**: [Synchronous Finality](/updates/synchronous-finality/) ## 2. Conditional Transactions Signet transactions can require outcomes on Ethereum. "Execute this swap only if I receive 1 ETH on L1." The protocol enforces the condition—if the L1 side doesn't happen, the Signet side reverts automatically. No partial fills. No abandoned assets. No gas wasted. > **Deep dive**: [Application Controlled Execution](/updates/application-controlled-execution/) ## 3. Competitive Fillers Who provides the L1 side of Signet's cross-chain swaps? Market participants called Fillers. They compete to fulfill your orders — the best price wins. Instead of extracting value from your transactions, Fillers use them in cross-chain bundles where both sides profit. Same actors, different incentives. > **Deep dive**: [The Filler Economy](/updates/the-filler-economy/) ## One Mental Model Users get instant cross-chain execution. Applications get atomic guarantees without bridge infrastructure. Developers get a single mental model instead of async complexity. | I want to... | Start here | |--------------|------------| | Build an app with cross-chain execution | [Solidity Examples](/updates/contracts-that-read-the-future/) | | Implement order creation and filling | [Building with Orders](/updates/building-with-orders/) | | Become a block builder | [Block Building Without Auctions](/updates/block-building-without-auctions/) | | Test on the public testnet | [Introducing Parmigiana](/updates/introducing-parmigiana/) | Questions? [Get in touch](https://t.me/anthspezzano). -------------------------------------------------------------------------------- ### Rebased Optimism URL: https://test.signet.sh/updates/rebased-optimism/ Published: 2026-02-10 -------------------------------------------------------------------------------- Signet is a synchronous rollup that extends Ethereum. Same block, same state, same finality. [Optimistic Thinking](/updates/optimistic-thinking/) covered the protocol architecture — why we built it, how correctness works, what we traded away. This piece is the application argument. ## Developer Experience Not because we built better development tools — though we did. Because we removed the constraints that made building hard in the first place. You're not working around a proving system or designing for withdrawal windows. When you want the chain to do something new for your application, you don't have to rebuild a fraud prover first. You get Orders, Fills, and atomic cross-chain execution — in the same Ethereum block. The tooling is everything you know and love. Same EVM, same contracts. The model has a few new pieces — conditional execution, cross-chain atomicity — and those are the parts worth learning. They're also the parts no other rollup can offer you. ## Programmatic Actors Signet's architecture favors programmatic actors — bots, keepers, agents, any software that needs to reason about on-chain state and act on it. The properties that matter for automated actors are the same ones [Optimistic Thinking](/updates/optimistic-thinking/) argued for: explicit events, deterministic execution, and atomic cross-chain settlement. An automated system can check *did this Fill event happen?* and branch on that. It can't reliably reason about a 7-day challenge window or probabilistic finality. The [TypeScript SDK](/docs/build-on-signet/transfers/exit-signet/#typescript) lets programmatic actors build full flows — L1 to L2, L2 to L1, multi-step coordination — from a single interface, against the same event-driven guarantees the protocol provides to everyone else. No special agent infrastructure. No separate API. Events and atomicity are exactly what orchestration requires. Everything else is extra. ## Building Without Permission Every design decision above exists because Signet has no proving system. That's not a simplification. It's the reason we can do things for applications that other rollups can't. Fault proofs create a ceiling on design. On Arbitrum, [customizing the state transition function](https://docs.arbitrum.io/launch-arbitrum-chain/customize-your-chain/customize-stf) means updating the fraud prover to recognize the new behavior as correct — otherwise, the prover sides with unmodified nodes and your chain loses its own dispute game. The process: modify the node, disable fraud proofs, rebuild the prover, update the WASM module root onchain, re-enable. For every change. The OP Stack has the same constraint through Cannon. If you spent three to five years building a proving system to do what rollups do out of the box, adding any nuance — any application-specific customization — sends you through a loop of redesigning, updating, and maintaining the prover. Nobody will willingly do that. You tell us your application needs deposits to execute before liquidations on the rollup, and we make that happen. You need swaps to settle before new positions open in your options protocol — we build that into the execution engine. Staking events need to precede withdrawals from your lending market — we write it into the block building rules. The state transition function, the execution engine, the [block builder set](/updates/block-building-without-auctions/) — all of it is on the table. You say jump, we say how high. Signet isn't off the rack. A general-purpose rollup is a cookie cutter. Deploy smart contracts permissionlessly — that's the value proposition, and that's where it ends. An app chain is bespoke: purpose-built for a single application. Signet offers both and isn't limited to *one* application's business logic. General-purpose execution with [application controlled](/updates/application-controlled-execution/) customization. The STF and rollup team should be catering to the needs of the application, not the other way around. Look at DeFi today. The protocols holding the most value — [Lido](https://defillama.com/protocol/lido), [Aave](https://defillama.com/protocol/aave), [Uniswap](https://defillama.com/protocol/uniswap), [Maker](https://defillama.com/protocol/makerdao) — are staking, lending, DEXs, vaults. Protocols like [Morpho](https://defillama.com/protocol/morpho) are deployed across half a dozen chains, each with its own fragmented liquidity, separate incentive campaigns, and duplicate operating infrastructure. Signet's same-block L1 access means applications can use Ethereum collateral directly — without bridging it, without fragmenting it, without running parallel operations on every chain. We're talking to several teams building in these spaces right now. We have an open invitation and a round table of technical founders working on lending protocols, vaults, DEXs, and financial infrastructure. If you're building at the edge of what's possible and the rollup you're on isn't keeping up — [reach out](https://t.me/anthspezzano). We're in active conversations and there's room for more. ## Where This Goes We're a small, independent, research-driven team with a decade in Ethereum. We've invented same-block cross-chain actions. Built the first synchronous rollup. No token. No venture capital pressure. And we think these design decisions will be necessary for every serious application eventually. It just might not be obvious today. These two pieces are our opening arguments. Next, we'll share explorations on how applications scale on Signet: - **Lending**: What happens when Ethereum-native collateral stays on L1 and cross-chain liquidations collapse into a single signed Order. - **Vaults**: What rebalancing looks like without 2–21 day settlement windows. - **DEXs**: Why cross-chain swaps don't need bridges. - **Agents**: What happens when agents own the full loop — monitoring, executing, coordinating — on an event-driven rollup. - **Derivatives**: How price-contingent execution settles options only when Ethereum oracle conditions are met — in the same block. - **Why No Token**: The unit economics problem, and what durable infrastructure actually looks like. If any of this is relevant to what you're working on, reach out. Mainnet is imminent. - [How Signet Works](/updates/how-signet-works/) - [Contracts That Read The Future](/updates/contracts-that-read-the-future/) - [Developer Docs](https://docs.signet.sh) -------------------------------------------------------------------------------- ### Optimistic Thinking URL: https://test.signet.sh/updates/optimistic-thinking/ Published: 2026-02-06 -------------------------------------------------------------------------------- Rollups are supposed to be a bet on Ethereum, not on isolated ecosystems, new governance tokens, or new trust assumptions. The bet is that Ethereum scales by extending its execution environment. All the tools you know. All the liquidity. All the finality guarantees. Just more room. That's not what's happening. The OP Stack, the most widely forked rollup framework, has inspired over a dozen one-click vampire attacks with optional fault proof systems. Users are isolated. Developers are fragmented. Time, attention, and capital drift from L1 into the silos of these Optimism and Arbitrum clones. Maybe two or three are worth mentioning, but for what? We've strayed too far from first principles. Signet brings it back, one block at a time. The rollup as intended: an extension of Ethereum. ## Proving vs. Executing If rollups aren't rushing to real fault proofs, and the economics don't clearly reward reaching Stage 2, then "optimistic" stops meaning *secure, credibly neutral execution with enforced correctness*. It starts meaning, in the optimistic case, *a fast chain you hope is operated by the right set of signers*. What application developers actually need is orthogonal to the fraud proof debate: fast, reliable withdrawals. Predictable settlement. Clear guarantees about what is and isn't final. Same-block cross-chain actions, not 7-day challenge windows. Those are execution and settlement problems. ## Events vs. Assumptions With traditional rollups, correctness depends on honest fault proof submission and an ecosystem that actually runs the infrastructure to challenge bad states. The system assumes execution is correct unless someone expensively proves otherwise. Signet inverts this. Correctness is validated during execution, not after. Events are the primitive: the system is built around *this event happened, therefore these transitions are valid*, not *someone might eventually prove this was wrong*. You cannot validate a rollup without also validating its host chain. Instead of fighting this dependency, we embraced it. An Order on Signet is only applied to rollup state if every corresponding Fill event exists on-chain. The execution engine checks this during block production, not in a challenge window days later. After years of deferred fault proofs, we're betting that correctness enforced during execution beats correctness verified after the fact. The challenge window is zero, because the validation happens in the block. Extensions work better than replacements. ## Cross-Chain Settlement The OP Stack promised a "Superchain": interconnected chains that talk to each other. In practice, we got rollup-to-rollup bridges without native interoperability to Ethereum L1, or clean semantics for cross-chain applications that need hard guarantees. The path that had to work from day one, rollup to Ethereum, was deprioritized in favor of intra-ecosystem interop. Signet enshrines [cross-chain transfers](/docs/learn-about-signet/cross-chain-transfers/) at the protocol-level. A user signs an [Order](/docs/build-on-signet/transfers/exit-signet/) specifying inputs and outputs across chains. Fillers fill both legs. Builders include them in the [same Ethereum block](/updates/synchronous-finality/). Both sides execute or neither does. No bridge contracts. No escrow. No partial fills. A filler's incentive to fill is completely economic end-to-end, never subsidized by unsustainable token emissions. Our early evidence will show how attractive this is. We'll be actively working with applications, developers, and fillers to understand where we can push things and iterate in real-time on the interface designs. ## Block Production and Economics Traditional rollups operate a centralized sequencer and a token. That token sits at the center of governance and — theoretically — value capture and security. Signet uses [round-robin builder rotation](/updates/block-building-without-auctions/) with [blind sequencer signing](/docs/learn-about-signet/simple-sequencing/) instead. Builders get predictable 8-second slots. The sequencer validates transaction structure without seeing contents; it cannot censor what it doesn't know. There is no Signet token. Revenue flows directly to builders and fillers. Every participant earns from economic activity from day one. Builders capture fees. Fillers capture MEV. Traditional rollups concentrate value capture in the sequencer — 100% of ordering power, 100% of revenue. Nothing for their participants. Signet redesigned this approach from the bottom up to include our partners *and* applications inherit a lot of first class ordering rights to prevent any toxic value leakage. No Signet token means no pseudo-governance gated decision making and no staking-based security — trade-in we accept because we think rollup economics should be wired to operating business logic, not propped up by inflated token emissions. There is no alternative agenda. We're [init4](https://x.com/init4tech) the tech. If any of this is the kind of rollup your application needs — [get in touch](https://t.me/anthspezzano) and tell us what you're building. - [How Signet Works](/updates/how-signet-works/) - [Contracts That Read The Future](/updates/contracts-that-read-the-future/) - [Developer Docs](https://docs.signet.sh)