# Signet - Full Documentation > Signet is a pragmatic Ethereum rollup with sustainable economic incentives This file contains the complete documentation for Signet. For a curated overview with links, see /llms.txt Last updated: 2025-11-04 ================================================================================ ## DOCUMENTATION-------------------------------------------------------------------------------- ### FAQ URL: https://signet.sh/docs/more-info/faq/ Description: Frequently asked questions about Signet -------------------------------------------------------------------------------- # FAQ {{< details title="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. {{< /details >}} {{< details title="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. {{< /details >}} {{< details title="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]({{< relref "/docs/learn-about-signet/cross-chain-transfers/" >}}). {{< /details >}} {{< details title="Is Signet suitable for all use cases?" >}} While Signet offers significant benefits for most users, it may not be suitable for all situations. 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. {{< /details >}} {{< details title="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. {{< /details >}} {{< details title="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]({{< relref "/docs/build-on-signet/ethereum-to-signet/passage/" >}}) for details. {{< /details >}} {{< details title="What is Pecorino?" >}} Pecorino is a private Ethereum testnet for rollup and application experimentation, available to the public for testing and validation. It includes RPC endpoints, faucet, explorer, and transaction cache infrastructure for development. See [Pecorino Quickstart]({{< relref "/docs/build-on-signet/pecorino/" >}}) for network configuration and contract addresses. {{< /details >}} {{< details title="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]({{< relref "/docs/learn-about-signet/cross-chain-transfers/" >}}) for more details. {{< /details >}} {{< details title="Do I need to run my own Ethereum or Signet node?" >}} No. You can use public RPC endpoints. For Pecorino testnet, see the [Pecorino Quickstart]({{< relref "/docs/build-on-signet/pecorino/" >}}) for endpoints. For block builders, RPC access can be configured via environment variables—running your own nodes is optional infrastructure. See [Environment Variables]({{< relref "/docs/bb-3f7d9e2a/run-a-builder/environment-variables/" >}}) for builder configuration. {{< /details >}} {{< details title="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. {{< /details >}} -------------------------------------------------------------------------------- ### Getting started with Signet URL: https://signet.sh/docs/build-on-signet/getting-started/ -------------------------------------------------------------------------------- # Getting Started with Signet {{< callout type="info" >}}Already familiar with the Signet system contracts? [Check out the Pecorino quickstart!]({{< relref "./pecorino/" >}}){{< /callout >}} Signet is a reimagining of the EVM rollup stack, built on Ethereum. Signet offers features that other rollups can't, including: {{< branded-list >}} - Instant bridging of assets from Ethereum - Native support for Ethereum transactions - Full EVM compatibility - Instant cross-chain transactions with Ethereum {{< /branded-list >}} Signet is designed to be easy to use, easy to integrate with, and easy to build on. System actions are exposed as smart contracts, so developers can build on Signet using familiar tools and languages. ## Quickstart Resources - [Move assets to Signet instantly]({{< relref "./ethereum-to-signet/passage/" >}}) - [Make a Signet Transaction from Ethereum]({{< relref "./ethereum-to-signet/transactor/" >}}) - [Build on-chain Orders in Solidity]({{< relref "./signet-to-ethereum/on-chain-orders/" >}}) - [Build off-chain Orders with Rust]({{< relref "./signet-to-ethereum/rust-orders/" >}}) - [Explore the Pecorino testnet]({{< relref "./pecorino/" >}}) -------------------------------------------------------------------------------- ### Pecorino Quickstart URL: https://signet.sh/docs/build-on-signet/pecorino/ Description: How to get started on developing with Signet on the Pecorino test network. -------------------------------------------------------------------------------- # Pecorino Quickstart Pecorino is a private Ethereum testnet for rollup and application experimentation, available to the public for testing and validation. This page contains key contract addresses and RPC endpoints for developers looking to quickly set up and interact with the Pecorino network. 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 or software that interacts with both host and rollup chains, [please reach out](mailto:hello@init4.technology)! ## Network Configuration | Key | Value | | ------------------------------ | --------------------------------------- | | Host Chain ID | 3151908 | | Rollup Chain ID | 14174 | | Deploy Height | 366 | | Native Gas Token | USD | | RPC Endpoint | https://rpc.pecorino.signet.sh | | Faucet | https://faucet.pecorino.signet.sh | | Rollup Explorer | https://explorer.pecorino.signet.sh | | Host Explorer | https://explorer-host.pecorino.signet.sh| | Transaction Cache API Endpoint | https://transactions.pecorino.signet.sh | ## Host System Contracts | Contract | Address | | -------------- | ------------------------------------------ | | [Zenith] | {{< copycode-inline >}}0xf17E98baF73F7C78a42D73DF4064de5B7A20EcA6{{< /copycode-inline >}} | | [HostOrders] | {{< copycode-inline >}}0x0A4f505364De0Aa46c66b15aBae44eBa12ab0380{{< /copycode-inline >}} | | [Passage] | {{< copycode-inline >}}0x12585352AA1057443D6163B539EfD4487f023182{{< /copycode-inline >}} | | [Transactor] | {{< copycode-inline >}}0x3903279B59D3F5194053dA8d1f0C7081C8892Ce4{{< /copycode-inline >}} | ## Rollup System Contracts | Contract | Address | | --------------- | ------------------------------------------ | | [RollupOrders] | {{< copycode-inline >}}0x000000000000007369676e65742d6f7264657273{{< /copycode-inline >}} | | [RollupPassage] | {{< copycode-inline >}}0x0000000000007369676e65742d70617373616765{{< /copycode-inline >}} | | WETH | {{< copycode-inline >}}0x0000000000000000007369676e65742d77657468{{< /copycode-inline >}} | | WBTC | {{< copycode-inline >}}0x0000000000000000007369676e65742d77627463{{< /copycode-inline >}} | ## Rollup Utility Contracts | Contract | Address | | ----------------------------------- | ------------------------------------------ | | [WUSD (Wrapped Native) Asset] | {{< copycode-inline >}}0x0000000000000000007369676e65742d77757364{{< /copycode-inline >}} | | [Permit2] | {{< copycode-inline >}}0x000000000022D473030F116dDEE9F6B43aC78BA3{{< /copycode-inline >}} | | [Gnosis Safe Factory] | {{< copycode-inline >}}0x8ff5C1D5233CA055cD536b2b87294d17f9160801{{< /copycode-inline >}} | | [Gnosis SafeL2] | {{< copycode-inline >}}0x2f2965efaCFc64Fb85dF1902260eB25C0c996195{{< /copycode-inline >}} | | [Safe CompatibilityFallbackHandler] | {{< copycode-inline >}}0xe59838EB7f251489b50940BD640326215420B936{{< /copycode-inline >}} | | [Deterministic Deployer] | {{< copycode-inline >}}0x4e59b44847b379578588920cA78FbF26c0B4956C{{< /copycode-inline >}} | [Zenith]: https://github.com/init4tech/zenith/blob/main/src/Zenith.sol [HostOrders]: https://github.com/init4tech/zenith/blob/main/src/orders/HostOrders.sol [Passage]: https://github.com/init4tech/zenith/blob/main/src/passage/Passage.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 [Transactor]: https://github.com/init4tech/zenith/blob/main/src/Transactor.sol [Permit2]: https://docs.uniswap.org/contracts/permit2/overview [WUSD (Wrapped Native) Asset]: https://github.com/islishude/uniswapv2-solc0.8/blob/main/contracts/test/WETH9.sol [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 -------------------------------------------------------------------------------- ### Simplifying the Rollup URL: https://signet.sh/docs/learn-about-signet/simplifying-the-rollup/ Description: 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. {{< branded-list >}} - 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 {{< /branded-list >}} 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"](https://prestwich.substack.com/p/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. -------------------------------------------------------------------------------- ### Working with Orders URL: https://signet.sh/docs/build-on-signet/signet-to-ethereum/orders/ Description: Move assets from Signet to Ethereum using Orders -------------------------------------------------------------------------------- # Working with Orders Signet Orders enable atomic, instant, cross-chain swaps between Signet and Ethereum. Orders specify assets in, assets out, and on what chain the assets out should be delivered. Orders can be created by smart contract execution via the [Orders Contract], or via an off-chain `SignedOrder` object. ## How Orders Work MEV Searchers (called Fillers) compete to fulfill each Order by providing the output tokens. Your input tokens are locked on Signet until a Filler completes the swap. **Orders are a form of direct interaction with the MEV ecosystem.** You can think of them as a way to express your intent to move assets across chains, while allowing the MEV market to find the best execution strategy. An Order has two main components: - **Inputs**: What you're providing on Signet - **Outputs**: The assets you want to receive, as well as the chain and address to which to deliver them. `Input` and `Output` structs are specified in the [`IOrders.sol`] interface. ## Implementation Paths Choose your implementation based on your stack: ### On-chain Orders in Solidity Build smart contracts that create, fill, or interact with Signet Orders on-chain. Perfect for: - Automated MEV capture - Flash loans across chains - Payment gating - Smart contract exits from Signet [Learn how to work with Solidity Orders]({{< relref "./on-chain-orders" >}}) ### Off-chain Orders in Rust Build applications that create and fill Signet Orders programmatically. Perfect for: - Market making bots - Order monitoring services - Cross-chain arbitrage - Custom filler strategies [Learn how to work with Rust Orders]({{< relref "./rust-orders/" >}}) ## Next Steps Start with the implementation path that matches your stack, or explore both to understand the full capabilities of Signet Orders. [Orders Contract]: https://github.com/init4tech/zenith/blob/main/src/orders/OrderOrigin.sol [`IOrders.sol`]: https://github.com/init4tech/zenith/blob/main/src/orders/IOrders.sol -------------------------------------------------------------------------------- ### EVM Behavior URL: https://signet.sh/docs/build-on-signet/evm-behavior/ Description: EVM modifications and differences between Signet and Mainnet EVM. -------------------------------------------------------------------------------- # EVM Behavior Signet is the most EVM-compatible rollup. This page describes the (very few) differences between Signet and Ethereum Mainnet EVM behavior. ## USD Native Asset The native asset on Signet is USD. USD has 18 decimals, like ETH on Ethereum Mainnet. See the [Passage]({{< relref "./ethereum-to-signet/passage/" >}}) contract for more information on how USD is minted. ## Inherited header values The following opcodes inherit the values of the Ethereum block: - `PREVRANDAO` — `block.difficulty` and `block.prevrandao` - `TIMESTAMP` — `block.timestamp` {{< callout type="info" >}}Signet blocks _always_ use the same timestamp as the current Ethereum block.{{< /callout >}} ## 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](https://www.evm.codes/precompiled), plus the following additional precompile: - secp256r1 signature verification as specified in [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md) at address `0x100`. -------------------------------------------------------------------------------- ### Glossary URL: https://signet.sh/docs/more-info/glossary/ Description: Definitions of key terms and concepts in Signet -------------------------------------------------------------------------------- # Glossary {{< details title="Blind Signing" >}} Blind signing is a security feature where a party (in this case, the sequencer) signs a piece of information without knowing its full contents. It's like signing a sealed envelope without being able to see what's inside. Key points: 1. The signer only sees a hash (a unique digital fingerprint) of the content, not the actual content itself. 2. This prevents the signer from selectively censoring or manipulating the content based on what it contains. 3. It enhances privacy and reduces the potential for bias or censorship. In Signet's context: The sequencer blind signs blocks. It only sees the block's hash and the builder's identity, not the actual contents of the block. This ensures fair and unbiased block inclusion while preventing potential censorship. {{< /details >}} {{< details title="Block Builders" >}} Block builders are specialized participants in a blockchain network who assemble and propose new blocks to be added to the blockchain. They're like puzzle makers who gather and arrange transactions into a format that fits the blockchain's rules. Traditionally: 1. Block builders collect pending transactions from the network's mempool (a pool of unconfirmed transactions). 2. They organize these transactions in a way that maximizes their profit (through transaction fees) while adhering to the network's rules. 3. In some systems, block builders compete to have their blocks chosen by proposers or validators. 4. They often use sophisticated algorithms and infrastructure to optimize block composition. Signet takes a different approach to block building compared to traditional systems: 1. Instead of using auctions where wealthy builders can dominate, Signet uses a round-robin style system. 2. A central sequencer assigns block production rights to different block builders in turns. 3. This approach aims to prevent centralization and ensure fairer participation among block builders. 4. The sequencer uses blind signing (as we discussed earlier) to prevent censorship and ensure unbiased block inclusion. {{< /details >}} {{< details title="Conditional Transactions" >}} Conditional transactions are operations that only execute if certain predefined conditions are met. They're like "if-then" statements in programming, but for blockchain transactions. Key points: 1. The transaction is only processed and finalized if all specified conditions are satisfied. 2. If any condition is not met, the entire transaction is cancelled as if it never happened. 3. This feature enables more complex and secure interactions, especially between Signet and Ethereum. In Signet's context: Conditional transactions are used for cross-chain transfers. They ensure that the transfer is fully executed in the same block on both chains. If the conditions aren't met, the transaction is invalidated and has no effect on Signet's state. {{< /details >}} {{< details title="State Roots" >}} State roots are like a cryptographic snapshot of the entire state of a blockchain at a specific point in time. They serve as a compact way to represent and verify all the accounts, balances, and smart contract data on the blockchain without needing to store or process the entire history of transactions. To break it down further: 1. Think of the blockchain as a giant ledger or database. 2. This ledger contains information about every account, its balance, and all the data stored in smart contracts. 3. The state root is a single, unique hash (a fixed-length string of characters) that represents the entire contents of this ledger at a specific block. 4. Any change to any part of the ledger, no matter how small, will result in a completely different state root. {{< /details >}} {{< details title="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](https://github.com/init4tech/zenith/blob/main/src/orders/OrderOrigin.sol) 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]({{< relref "/docs/build-on-signet/signet-to-ethereum/orders/" >}}) for implementation details. {{< /details >}} {{< details title="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]({{< relref "/docs/build-on-signet/signet-to-ethereum/orders/#how-orders-work" >}}) for more details. {{< /details >}} {{< details title="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]({{< relref "/docs/bb-3f7d9e2a/customizing-a-builder/bundle-guarantees/" >}}) for details. {{< /details >}} {{< details title="Host Chain / Rollup Chain" >}} Terminology used in Signet configuration and APIs. Host Chain refers to Ethereum. Rollup Chain refers to Signet. On the Pecorino testnet, Host Chain ID is 3151908 and Rollup Chain ID is 14174. See [Pecorino Quickstart]({{< relref "/docs/build-on-signet/pecorino/" >}}) for network configuration. {{< /details >}} {{< details title="Sequencer" >}} Sequencers are special entities in rollup systems that are responsible for ordering and batching transactions. Think of a sequencer as a traffic controller for blockchain transactions. Most rollups use a single centralized Sequencer with near-total control over transaction ordering. Signet's sequencer doesn't actually order transactions. Instead, it delegates that to block builders, and then co-signs the blocks. 1. Round-robin assignment: Instead of using auctions, the sequencer assigns block production rights to different block builders in turns. 2. Blind signing: The sequencer only sees the block's hash and the builder's identity, not the actual contents of the block. This prevents selective censorship. 3. Simplicity: Signet's sequencer is designed to be simple, easy to maintain, and less prone to errors. {{< /details >}} -------------------------------------------------------------------------------- ### Moving Assets to Signet URL: https://signet.sh/docs/build-on-signet/ethereum-to-signet/passage/ Description: Move ETH and ERC-20 tokens from Ethereum to Signet -------------------------------------------------------------------------------- # Moving Assets to Signet {{< callout type="info" title="Supported Assets" >}} Signet currently supports bridging **ETH**, **USDC**, **USDT**, and **WBTC** from Ethereum. Custom assets can be created on Signet but cannot be bridged from Ethereum. Contact the Signet team to add support for additional assets. {{< /callout >}} The [Passage](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) contract helps move assets from Ethereum to Signet instantly. Signet nodes listen for `Passage` events, and mint tokens on Signet in the **same block**. Consult the [Pecorino Quickstart]({{< relref "../pecorino/" >}}) guide for contract addresses and RPC endpoints. ## Setup **Solidity (ABI):** Download the Passage ABI from [Passage ABI] ```bash curl -O https://signet.sh/docs/abis/Passage.abi.json ``` **Solidity (Source):** The Passage contract is open source ```bash forge install https://github.com/init4tech/zenith ``` **Rust:** Alloy bindings are available via the [signet-bindings](https://docs.rs/signet-bindings/latest/signet_bindings/) crate ```bash cargo add signet-bindings ``` ## Overview `Passage.sol` exposes a simple interface: **Move ETH to Signet:** ```solidity enter(address rollupRecipient) ``` The `fallback` and `receive` functions also move ETH to Signet, with `msg.sender` as recipient. **Move ERC-20 tokens to Signet:** ```solidity enterToken(address rollupRecipient, address token, uint256 amount) ``` Requires prior `approve` of Passage to spend tokens. Passage can be observed using the `Enter` and `EnterToken` events. The `Enter` event is fired whenever ETH is bridging to Signet, and `EnterToken` is fired when ERC-20 tokens are bridged. The Signet node listens for these events directly, so if the event fired, the tokens were bridged. ## Code Examples {{< details title="Solidity" >}} Passage is available as a Solidity contract or ABI. See the [Setup](#setup) section above. ```solidity contract YourContract { Passage public passage; IERC20 public token; constructor(address _passage, IERC20 _token) { passage = Passage(_passage); token = _token; token.approve(_passage, type(uint256).max); } // Enter on behalf of a user function bridgeETH() external payable { passage.enter{value: msg.value}(msg.sender); } // Move ERC-20 tokens to Signet function bridgeToken(uint256 amount) external { token.transferFrom(msg.sender, address(this), amount); passage.enterToken(address(token), msg.sender); } } ``` {{< /details >}} {{< details title="Cast" >}} To enter the rollup, Send ETH directly to the Passage contract: ```bash # Using cast cast send $PASSAGE_ADDRESS \ --value 1ether \ --rpc-url $HOST_CHAIN_RPC \ --private-key $PRIVATE_KEY ``` Entering with tokens requires multiple transactions: ```bash # 1. Approve Passage cast send $TOKEN_ADDRESS \ "approve(address,uint256)" \ $PASSAGE_ADDRESS, $AMOUNT \ --rpc-url $HOST_CHAIN_RPC \ --private-key $PRIVATE_KEY # 2. Call Passage to bridge tokens # See Passage.sol for the exact function name and parameters cast send $PASSAGE_ADDRESS \ "enterTokens(address,address,uint256)" \ $SIGNET_RECIPIENT, $TOKEN_ADDRESS, $AMOUNT \ --rpc-url $HOST_CHAIN_RPC \ --private-key $PRIVATE_KEY ``` {{< /details >}} {{< details title="Typescript" >}} ```jsx // Using ethers.js const tx = await signer.sendTransaction({ to: PASSAGE_ADDRESS, value: ethers.parseEther("1.0"), }); await tx.wait(); ``` Listen for events: ```jsx import { ethers } from "ethers"; const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com"); const passage = new ethers.Contract( PASSAGE_ADDRESS, PASSAGE_ABI, // Get ABI from contract source provider ); // Listen for events // Event names and signatures from Passage.sol passage.on("Enter", (...args) => { console.log("ETH bridged:", args); }); passage.on("EnterToken", (...args) => { console.log("Token bridged:", args); }); ``` {{< /details >}} {{< details title="Rust" >}} ```rust let passage = PassageContract::new( signet_constants::pecorino::HOST_PASSAGE, provider.clone(), ); // Enter the rollup from your EOA passage.enter().value(eth_in_wei).send(rollup_recipient).await?; ``` {{< /details >}} {{< callout type="info" >}}Check [Passage.sol](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) for the exact event signatures.{{< /callout >}} ## Next Steps Send a rollup transaction using the [Transactor]({{< relref "./transactor" >}}) contract. [Passage ABI]: /abis/Passage.abi.json -------------------------------------------------------------------------------- ### No Proofs or State Roots URL: https://signet.sh/docs/learn-about-signet/no-proofs-or-state-roots/ Description: How Signet eliminates proving overhead for better performance -------------------------------------------------------------------------------- # No Proofs or State Roots {{< callout type="info" title="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 {{< /callout >}} 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]({{< relref "/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 {{< callout type="info" title="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 {{< /callout >}} -------------------------------------------------------------------------------- ### On-chain Orders in Solidity URL: https://signet.sh/docs/build-on-signet/signet-to-ethereum/on-chain-orders/ Description: Build smart contracts that create and interact with Signet Orders -------------------------------------------------------------------------------- # On-chain Orders in Solidity Build smart contracts that create, fill, or interact with Signet Orders. These examples demonstrate practical patterns for capturing MEV, automating exits, and creating novel cross-chain primitives. ## Setup **Solidity (Source):** Install the Signet Orders contracts ```bash forge install https://github.com/init4tech/zenith ``` **Solidity (ABI):** Download the Orders ABI ```bash curl -O https://signet.sh/docs/abis/Orders.abi.json ``` **Examples:** View example contracts at [signet-sol](https://github.com/init4tech/signet-sol) The example repository demonstrates practical patterns for: - Flash loans - Quick exits with fees - Payment gating - MEV capture Study these examples to understand how to build with Signet Orders. ## Example Contracts All examples use the Signet Orders system to enable cross-chain, instant, atomic, and composable operations. {{< details title="SignetStd.sol - System Configuration" description="Auto-configure Signet system parameters based on chain ID. Use this as a base for contracts that need to interact with Signet." >}} **When to use:** - You're building a contract that creates or interacts with Orders - You need to reference Signet system contracts - You want chain-agnostic Signet integration ```solidity import {SignetStd} from "./SignetStd.sol"; contract YourContract is SignetStd { function createOrder() external { // Automatically has access to: // - rollupOrders: The Orders contract address // - permit2: The Permit2 contract address // - Other Signet system parameters } } ``` Source: [SignetStd.sol](https://github.com/init4tech/signet-sol/blob/main/src/SignetStd.sol) {{< /details >}} {{< details title="Flash.sol - Cross-Chain Flash Loans" description="Flash borrow any asset by using an Order where the Output becomes the Input to its own Order." >}} **When to use:** - You need temporary liquidity for a transaction - You want to perform cross-chain arbitrage - You need to borrow assets without upfront collateral **How it works:** 1. Request a flash loan of X tokens 2. Searchers provide the tokens (knowing they'll be repaid) 3. Your contract executes logic with the borrowed assets 4. The Order output repays the input, completing the cycle ```solidity // Example: Flash borrow WETH for arbitrage flashBorrow(wethAddress, amount, arbitrageCalldata); ``` Source: [Flash.sol](https://github.com/init4tech/signet-sol/blob/main/src/examples/Flash.sol) {{< /details >}} {{< details title="GetOut.sol - Quick Exit with Fee" description="Exit Signet by offering searchers a 50 basis point fee. The simplest way to move assets from Signet to Ethereum." >}} **When to use:** - You want a one-line function to exit Signet - You're willing to pay a small fee for immediate exit - You're building a UI that needs a simple exit mechanism ```solidity // Exit Signet with a 50bps fee getOut(tokenAddress, amount, recipient); ``` **How it works:** - Your contract locks tokens on Signet - Creates an Order offering 99.5% of tokens on Ethereum - Searchers fill the order for the 0.5% profit - You receive tokens on Ethereum instantly Source: [GetOut.sol](https://github.com/init4tech/signet-sol/blob/main/src/examples/GetOut.sol) {{< /details >}} {{< details title="PayMe.sol - Payment Gating" description="Gate contract execution behind a payment using an Order with no inputs. The calling contract doesn't need to manage cash flow--any third party can fill the payment order." >}} **When to use:** - You want users to pay for contract execution - You don't want your contract to handle payment logic - You want to allow third-party payment (gasless transactions) **How it works:** - Your contract creates an Order with only outputs (payment required) - Contract execution is invalid unless someone fills the Order - Unlike `msg.value` checks, the payer can be anyone - Greatly simplifies payment logic ```solidity function executeWithPayment() external { // Create payment order payMe(usdcAddress, 10e6); // Require 10 USDC payment // Your contract logic here // Only executes if payment Order is filled } ``` Source: [PayMe.sol](https://github.com/init4tech/signet-sol/blob/main/src/examples/PayMe.sol) {{< /details >}} {{< details title="PayYou.sol - MEV Capture and Bounties" description="Generate MEV by offering an Order with no outputs. This creates a bounty for calling your contract, functioning as an incentivized scheduling system." >}} **When to use:** - You want to incentivize someone to call your contract - You're creating an automated system that needs execution - You want to capture MEV produced by your protocol **How it works:** - Your contract creates an Order with only inputs (no outputs required) - Searchers compete to call your contract to claim the bounty - Functions as an incentivized scheduling/execution system ```solidity function executeAndPay() external { // Your contract logic that generates value performArbitrage(); // Pay searchers for executing payYou(wethAddress, 0.01 ether); // Offer 0.01 ETH bounty } ``` **Use cases:** - Liquidation systems - Automated rebalancing - Scheduled maintenance - MEV extraction from your protocol Source: [PayYou.sol](https://github.com/init4tech/signet-sol/blob/main/src/examples/PayYou.sol) {{< /details >}} {{< callout type="info" title="Building your own contract" >}} Use these patterns as building blocks: 1. **Inherit SignetStd** for automatic configuration 2. **Combine patterns** (e.g., PayMe + PayYou for payment flows) 3. **Test thoroughly** with `forge test` 4. **Deploy** to Signet testnet first {{< /callout >}} -------------------------------------------------------------------------------- ### Ethereum-driven Transactions URL: https://signet.sh/docs/build-on-signet/ethereum-to-signet/transactor/ Description: Execute transactions from Ethereum to Signet with guaranteed inclusion -------------------------------------------------------------------------------- # Ethereum-driven Transactions The [`Transactor` Contract](https://github.com/init4tech/zenith/blob/main/src/Transactor.sol) creates transactions on Signet from Ethereum. Transactions made via the `Transactor` always execute on Signet at the end of the current block, bypassing any possibility of builder censorship. Consult the [Pecorino Quickstart]({{< relref "../pecorino/" >}}) guide for contract addresses and RPC endpoints. ## Setup **Solidity (ABI):** Download the Transactor ABI from [Transactor ABI](/abis/Transactor.abi.json) ```bash curl -O https://signet.sh/docs/abis/Transactor.abi.json ``` **Solidity (Source):** The Transactor contract is open source ```bash forge install https://github.com/init4tech/zenith ``` **Rust:** Alloy bindings are available via the [`signet-bindings`](https://docs.rs/signet-bindings/latest/signet_bindings/) crate ```bash cargo add signet-bindings ``` ## Overview `Transactor.sol` exposes a basic EVM transaction as a single function: ```solidity function transact( address to, bytes calldata data, uint256 value, uint256 gas, uint256 maxFeePerGas ) external payable ``` Calling the `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` field is the amount of ETH in wei to send **on the rollup**. The `msg.value` of the `transact` call will be bridged to Signet, and could be more or less than `value`. I.e. the call `transactor.transact{value: 5 ether}(.., 1 ether, ...)` will send 5 ETH to Signet, but only 1 ETH will be used to invoke the `to` address. Transactions 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 it may revert or be dropped by the [Signet Orders]({{< relref "../signet-to-ethereum/orders/" >}}) system). {{< callout type="success" title="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 {{< /callout >}} {{< callout type="danger" title="Don't use Transactor when..." >}} - You're just moving assets (use [Passage](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) instead) - Gas cost is a primary concern (direct Signet txs are cheaper) - You don't need L1-triggered execution {{< /callout >}} ## Code Examples {{< details title="Solidity" >}} ```solidity contract YourContract { Transactor public transactor; constructor(Transactor _transactor) { transactor = _transactor; } // Execute a function on Signet from Ethereum function executeOnSignet( address signetTarget, bytes calldata functionData ) external { transactor.transact( signetTarget, functionData, 0, // value on Signet 1_000_000, // gas limit on Signet 100 gwei // max fee per gas on Signet ); } // Emergency action on Signet function emergencyAction(address signetContract) external onlyOwner { // Encode the emergency function call bytes memory data = abi.encodeWithSignature("emergencyPause()"); executeOnSignet(signetContract, data); } } ``` {{< /details >}} {{< details title="Monitoring Transactor activity in JavaScript/TypeScript" >}} Listen for Transactor events to track Host-driven transactions: ```jsx import { ethers } from "ethers" const provider = new ethers.JsonRpcProvider("https://eth.llamarpc.com") const transactor = new ethers.Contract( TRANSACTOR_ADDRESS, TRANSACTOR_ABI, // Get ABI from contract source provider ) // Listen for Host-driven transactions // Event name and signature from Transactor.sol transactor.on("Transact", (...args) => { console.log("Host-driven execution:", args) // Decode the calldata if needed const [from, to, data] = args // Adjust based on actual event console.log(`${from} Host-driven execution on ${to}`) }) ``` {{< /details >}} ## Related Resources - [Signet Orders]({{< relref "../signet-to-ethereum/orders/" >}}) - [`signet-bindings` crate](https://docs.rs/signet-bindings/latest/signet_bindings/) - [Transactor ABI](/abis/Transactor.abi.json) - [`Transactor` Contract Source](https://github.com/init4tech/zenith/blob/main/src/Transactor.sol) - [Pecorino Quickstart]({{< relref "../pecorino/" >}}) -------------------------------------------------------------------------------- ### Off-chain Orders in Rust URL: https://signet.sh/docs/build-on-signet/signet-to-ethereum/rust-orders/ Description: Create Signet Orders in Rust -------------------------------------------------------------------------------- # Off-chain Orders in Rust This page will walk you through creating and submitting off-chain Orders using Rust and the Signet SDK. The [Orders](https://github.com/init4tech/zenith/blob/main/src/orders/) contract enables trustless, cross-chain asset swaps between Signet and Ethereum. Signet nodes listen for Order and Filled events, and ensure that all transactions that emit Orders have corresponding Fills executed on the destination chain in the same block. Order events are emitted on Signet, while Filled events may be emitted on either Ethereum or Signet. Off-chain orders are pre-signed, using [Permit2](https://docs.uniswap.org/contracts/permit2/overview), and may be executed by a third-party filler, allowing users to perform gasless swaps. {{< callout type="warning" title="Set competitive prices on your orders" >}} Signet Orders guarantee that if their Outputs are not Filled, no transaction will be executed on Signet. However, there is no guarantee that any searcher will choose to Fill your Order. Make sure to set competitive prices on your orders to ensure they are filled! {{< /callout >}} ## Setup Set up your Rust project ```bash cargo new my_cool_app --bin ``` Install the required Signet crates ```bash cargo add signet-zenith cargo add signet-constants cargo add signet-types cargo add signet-tx-cache ``` Ensure your account has approved [Permit2](https://docs.uniswap.org/contracts/permit2/overview) to spend your input tokens. Consult the [Pecorino Quickstart]({{< relref "../pecorino/" >}}) guide for contract addresses and RPC endpoints. ## Creating an Order The [signet-types](http://docs.rs/signet-types/latest/signet_types/) crate provides a simple order builder via the [UnsignedOrder](https://docs.rs/signet-types/latest/signet_types/signing/order/struct.UnsignedOrder.html) struct, which can be used to build orders. We can start by creating a simple order that swaps 1 WETH on Signet for 1 WETH on Ethereum: ```rust use signet_types::signing::order::{UnsignedOrder}; use signet_constants::pecorino as constants; let mut order = UnsignedOrder::default() .with_input( constants::RU_WETH, U256::from(1e18), // 1 WETH ).with_output( constants::HOST_WETH, U256::from(1e18), your_address, 1, // Ethereum mainnet ); ``` The `UnsignedOrder` struct also provides methods to sign orders, using any alloy signer. The signer requires that you provide the `constants` object, so that the permit2 signer can correctly derive the domain separator. ```rust use signet_types::signing::order::{UnsignedOrder}; use signet_constants::pecorino as constants; let signed = UnsignedOrder::default() .with_input(token_address, amount) .with_output(token_address, amount, recipient, chain_id) .with_chain(constants) .with_nonce(permit2_nonce) .sign(&signer).await?; ``` ## Submitting an Order Once signed, the order can be submitted to the Signet network via the Signet tx cache. The tx cache makes the Order available to Searchers, who will include it in execution bundles. ```rust use signet_tx_cache::TxCache; let tx_cache = TxCache::pecorino(); tx_cache.forward_order(signed_order).await?; ``` For on-chain order creation, check out [Solidity Orders]({{< relref "./on-chain-orders/" >}}). -------------------------------------------------------------------------------- ### Permissioned Roles URL: https://signet.sh/docs/more-info/permissioned-roles/ Description: 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 transparent and logged on-chain through events. This provides auditability while allowing the protocol to evolve over time. -------------------------------------------------------------------------------- ### Simple Sequencing URL: https://signet.sh/docs/learn-about-signet/simple-sequencing/ Description: Signet's approach to transaction ordering and inclusion -------------------------------------------------------------------------------- # Simple Sequencing {{< callout type="info" title="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 {{< /callout >}} ## 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. {{< callout type="warning" title="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. {{< /callout >}} {{< image src="mevboost.png" alt="Block builder market share showing the majority of blocks built by two builders" caption="Block builder market share statistics from [MEVboost.pics](https://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. {{< callout type="info" title="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. {{< /callout >}} -------------------------------------------------------------------------------- ### Cross-chain transfers URL: https://signet.sh/docs/learn-about-signet/cross-chain-transfers/ Description: How assets move seamlessly between chains -------------------------------------------------------------------------------- # Cross-chain transfers {{< callout type="info" title="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 {{< /callout >}} ## 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. {{< callout type="info" >}} 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. {{< /callout >}} {{< details title="Example: Moving assets from Ethereum to Signet" >}} The [Passage](https://github.com/init4tech/zenith/blob/main/src/passage/Passage.sol) contract facilitates asset transfers from Ethereum to Signet. A user wants to move 10 ETH from Ethereum to Signet: 1. User sends 10 ETH to the Signet/Passage contract on Ethereum. 2. The contract emits an `Enter` event. 3. Signet Rollup Node observes the event. 4. Rollup Node mints 10 ETH to the user's address on Signet. This process is permissionless and requires no action on Signet from the user. {{< /details >}} ## Moving from Signet to Ethereum Signet introduces [Conditional Transactions]({{< relref "/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. {{< callout type="success" title="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. {{< /callout >}} {{< details title="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. 1. Some Filler accepts this order by sending 5 ETH to the user on Ethereum. 2. The conditional transaction is now valid. 3. 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. {{< /details >}} {{< callout type="info" title="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 {{< /callout >}} ================================================================================ ## RECENT UPDATES -------------------------------------------------------------------------------- ### Signet Orders URL: https://signet.sh/updates/signet-orders/ Published: 2025-08-28 -------------------------------------------------------------------------------- Market-driven cross-chain execution requires practical implementation patterns. This guide provides working code for placing and filling Orders on Signet, demonstrating how applications can leverage competitive fillers for instant cross-chain operations. Building on Signet's [simplified atomicity](https://signet.sh/updates/simplified-atomicity/) and [settlement system](https://signet.sh/updates/settlement-system/), these examples show how to implement the order flow that powers same-block cross-chain execution. ## Implementation Components Three core components enable Order-based applications: - **Order Creation**: Applications express user intent through signed Permit2 structures - **Order Filling**: Market participants compete to fulfill orders for profit opportunities - **Bundle Coordination**: Atomic execution ensures all-or-nothing settlement The [`signet-orders`](https://github.com/init4tech/signet-orders) repository provides reference implementations for each component using utilities from [`signet-sdk`](https://github.com/init4tech/signet-sdk). ## Filler Implementation **Code: [`src/filler.rs`](https://github.com/init4tech/signet-orders/blob/main/src/filler.rs)** The `Filler` struct demonstrates the steps required to fill Signet Orders competitively: ```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 } } ``` Production fillers extend this pattern with custom business logic: - **Profitability**: Calculate spread opportunities across order sets - **Inventory**: Source liquidity through swaps when needed - **Competition**: Evaluate win probability against other fillers ## Filling Strategies The implementation demonstrates two complementary approaches: ### Aggregate Execution (`fill`) ```rust pub async fn fill(&self, orders: Vec) -> Result<()> { // Submit all Orders/Fills in single Bundle // Atomic execution: all succeed or none do } ``` **Benefits:** - **Gas efficiency**: Batched execution reduces transaction costs - **Capital optimization**: Reuse inputs from one order to fill another - **Complex strategies**: Enable sophisticated cross-order arbitrage **Trade-offs:** - **All-or-nothing**: Single order failure breaks entire bundle - **Complexity**: Requires pre-validation of order state ### Individual Execution (`fill_individually`) ```rust pub async fn fill_individually(&self, orders: Vec) -> Result<()> { // Submit each Order/Fill in separate Bundle // Independent execution: orders succeed or fail separately } ``` **Benefits:** - **Simplicity**: Rely on builder simulation instead of pre-checking - **Resilience**: Failed orders don't affect successful ones - **Parallel processing**: Multiple strategies can run simultaneously **Trade-offs:** - **Higher gas costs**: Individual transaction overhead per order - **Limited optimization**: Cannot reuse capital across orders ## Order Creation **Code: [`src/order.rs`](https://github.com/init4tech/signet-orders/blob/main/src/order.rs)** The `SendOrder` struct provides the application-side implementation for initiating orders: ```rust impl SendOrder { pub async fn initiate_order(&self, order: OrderSpec) -> Result<()> { // 1. Construct Permit2 authorization for inputs let permit = self.build_permit2(&order.inputs).await?; // 2. Sign order with user's key let signed_order = self.sign_order(permit, &order.outputs).await?; // 3. Submit to Transaction Cache for filler discovery self.tx_cache.submit_order(signed_order).await } } ``` Applications integrate this pattern to offer users instant cross-chain operations without managing bridge infrastructure or withdrawal periods. ## Complete Roundtrip Example **Code: [`bin/roundtrip.rs`](https://github.com/init4tech/signet-orders/blob/main/bin/roundtrip.rs)** The roundtrip example demonstrates end-to-end order flow: 1. **Construct Order**: Define input/output tokens and amounts 2. **Submit Order**: Send signed order to Transaction Cache 3. **Fill Order**: Compete with other fillers to execute 4. **Verify Settlement**: Confirm atomic cross-chain execution ```bash # Configure environment export CHAIN_NAME=pecorino export RU_RPC_URL=https://rpc.pecorino.signet.sh/ export SIGNER_KEY=[AWS KMS key ID or local private key] export SIGNER_CHAIN_ID=14174 # Run rollup-to-host swap cargo run --bin order-roundtrip-example # Run rollup-to-rollup swap cargo run --bin order-roundtrip-example -- --rollup ``` The example handles both AWS KMS and local private key signing, demonstrating production-ready key management patterns. ## Setup Requirements **Fund Your Key** The signing key must hold: - **Input tokens**: Assets being swapped from (rollup) - **Output tokens**: Assets being provided to user (host and/or rollup) - **Gas tokens**: ETH (Host) or USD (Rollup) for transaction fees **Configure Permit2 Approvals** Enable Permit2 to spend relevant tokens: ```bash cast send [TOKEN_ADDRESS] "approve(address,uint256)" \\ 0x000000000022D473030F116dDEE9F6B43aC78BA3 \\ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff \\ --rpc-url $RPC_URL ``` Permit2 uses consistent addresses across Pecorino and Ethereum mainnet, simplifying multi-chain applications. ## Bundle Execution Model Orders execute through Signet's atomic bundle system: **Block-Specific Execution**: Bundles target specific blocks for deterministic inclusion **Retry Pattern**: Failed bundles can be resubmitted for subsequent blocks **Atomic Guarantees**: All transactions in bundle succeed or none do ```rust // Bundle construction with host fills 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 allowed } }; ``` This model enables applications to offer users the same UX as centralized services while maintaining decentralized execution. ## Market Dynamics Order-based execution creates competitive markets that benefit users: - **Filler Competition**: Multiple parties compete to fill orders, driving efficient pricing - **Capital Efficiency**: Fillers optimize inventory across chains rather than maintaining idle liquidity pools - **Execution Incentives**: Better filling strategies capture more volume and profit Applications benefit from this competition without building internal market-making infrastructure. ## Production Considerations - **Business Logic**: Implement custom profitability analysis for your specific use case - **Key Management**: Use hardware security modules or key management services for production **Monitoring**: Track order fill rates and competitive positioning - **Capital Strategy**: Plan inventory management across supported chains - **Error Handling**: Implement retry logic for failed bundles and network interruptions - **Gas Optimization**: Consider aggregate vs individual filling strategies based on order patterns ## Integration Patterns - **Cross-chain DeFi**: Enable instant cross-chain positions without bridge delays - **Payment Systems**: Route payments optimally across chains based on liquidity - **Arbitrage Bots**: Capture price differences while providing user services - **Wallet Interfaces**: Offer seamless cross-chain swaps through order abstraction ## Build with Orders The order system transforms cross-chain operations from complex infrastructure challenges into simple market interactions. Applications post orders, competitive fillers provide execution, users get instant settlement. **Resources:** - [`signet-orders`](https://github.com/init4tech/signet-orders) - Complete example implementations - [`signet-sdk`](https://github.com/init4tech/signet-sdk) - Core types and utilities **Get Started:** - [Testnet Faucet](https://faucet.pecorino.signet.sh/) - Fund your development keys - [Pecorino Explorer](https://explorer.pecorino.signet.sh/) - Monitor order execution Start building applications that leverage competitive execution rather than fighting it. Orders enable market-driven cross-chain operations that scale with demand. **Questions about implementation patterns?** [Reach out](mailto:hello@init4.technology) to discuss specific integration approaches. -------------------------------------------------------------------------------- ### Settlement System URL: https://signet.sh/updates/settlement-system/ Published: 2025-06-04 -------------------------------------------------------------------------------- Traditional rollups lock capital and introduce: - **Multi-step withdrawal processes**: Initiate → Wait → Release - **Multi-day fraud proof windows**: Capital remains locked and unproductive This design creates a poor experience for users, builders, and solvers. ## Market-Based Settlement Signet eliminates the complicated withdrawal process and unnecessary delays through swaps by: **1. Synchronized Block Production** - Identical timestamps ensure deterministic ordering - Fork-choice rule maintains consensus alignment **2. Atomic Cross-Chain Execution** - Same-block finality - Conditional transaction enforcement **3. Market-Driven Price Discovery** - Competitive filler ecosystem - Real-time liquidity provision Signet is the only chain to achieve same-block cross chain settlement and it starts with our synchronized block architecture. ### Concurrent Block Production ![concurrent-block-production.png](concurrent-block-production.png) This 1:1 coupling enables deterministic state transitions. Every Signet block corresponds to exactly one Ethereum block, eliminating timing discrepancies. ### Order System Architecture Orders express atomic intent through Permit2, enabling gasless authorization: ```rust pub struct SignedOrder { pub permit: Permit2Batch, // Single signature authorization pub outputs: Vec, // Desired assets and destinations } pub struct Output { pub token: Address, // Asset identifier pub amount: Uint<256, 4>, // Precise amount pub recipient: Address, // Destination address pub chainId: u32, // Target chain } ``` **Order Lifecycle:** 1. **Creation**: User signs intent with ~10 minute validity window 2. **Discovery**: Broadcast to transaction cache for filler evaluation 3. **Execution**: Atomic settlement within single block 4. **Finalization**: Immediate availability on destination chain ### Settlement Mechanics: Inverted Execution Signet’s approach to atomicity is in transaction ordering enforcement: ![settlement-mechanics.png](settlement-mechanics.png) The `OrderDetector` enforces atomicity by validating that every order has corresponding fills before allowing transaction execution. This prevents partial settlements through deterministic state validation: ```rust impl OrderDetector { fn validate_transaction(&self, tx: &Transaction) -> Result<(), Error> { // Check if transaction emits Order event if let Some(order) = self.detect_order(tx) { // Verify all outputs have corresponding fills for output in order.outputs { if !self.has_sufficient_fill(output) { return Err(Error::InsufficientFill); } } // Consume fill amounts to prevent double-spending self.consume_fills(order.outputs); } Ok(()) } } ``` **Key Benefits:** - Fill transactions must mine before Initiate transactions - Failed fills result in automatic Initiate rejection - No intermediate states or partial executions ### Capital Efficiency Traditional rollups lock capital for extended periods. Signet enables continuous deployment: ![capital-velocity.png](capital-velocity.png) {{< callout type="info" >}} While traditional rollups process transactions continuously, settlement requires days. Signet settles every transaction in seconds. {{< /callout >}} This enables strategies previously impossible on other chains: **1. Intra-Block Arbitrage** - Execute multiple trades within single 12-second block - Compound returns through circular trading paths - Eliminate sequential execution risk **2. Dynamic Inventory Management** - Real-time cross-chain balance optimization - Just-in-time liquidity provision - Zero idle capital **3. Multi-Order Aggregation** - Net positions across multiple orders - Reduce transaction costs through batching - Maximize capital efficiency per block ### Bundle Construction Fillers aggregate multiple orders into atomic execution bundles: ```rust async fn construct_bundle(&self, orders: &[SignedOrder]) -> Result { // Aggregate orders by destination chain let aggregated = self.aggregate_by_chain(orders); // Sign fills for each destination let signed_fills = self.sign_fills(&aggregated).await?; // Build transaction sequence with proper ordering let txs = self.sequence_transactions(&signed_fills, orders).await?; // Extract cross-chain coordination data let host_fills = signed_fills.get(ÐEREUM_CHAIN_ID); // Atomic bundle with deterministic execution Ok(SignetEthBundle { host_fills, // Ethereum-side actions bundle: EthSendBundle { txs, // Signet-side transactions block_number: self.target_block(), reverting_tx_hashes: vec![], // No reverts allowed }, }) } ``` **Error Handling:** - Invalid signatures → Bundle rejected pre-execution - Insufficient liquidity → Fill transaction reverts - Gas exhaustion → Entire bundle fails atomically ### Market Efficiencies: Multiple fillers evaluate each order simultaneously, creating competitive pricing: ![price-discovery.png](price-discovery.png) - Multiple fillers evaluate each order simultaneously - Competition drives spreads toward equilibrium - Price discovery occurs every 12 seconds - No single filler controls market pricing - Capital availability across chains ### Filler Infrastructure Implement custom market-making strategies using the Signet SDK: ```rust // Custom filler implementation impl FillerStrategy for MyFiller { async fn evaluate_order(&self, order: &SignedOrder) -> Option { // Implement custom pricing logic let profit_margin = self.calculate_margin(order)?; // Check inventory across chains let has_liquidity = self.check_inventory(order).await?; // Evaluate competition let competitive = self.estimate_win_probability(order); if profit_margin > self.min_margin && has_liquidity && competitive > 0.3 { Some(FillDecision::Accept) } else { None } } } ``` - Gas cost optimization - Inventory rebalancing costs - Competition assessment - Risk-adjusted profit margins ## Protocol-Level Markets Signet's architecture embeds market mechanics at the protocol level: ![protocol-level-markets.png](protocol-level-markets.png) Every application built on Signet is enabled with instant cross-chain settlement. ## Cross-Chain Settlement Opportunities Whether it’s building user applications, providing liquidity, or executing orders, every builder benefits from the speed of settlement to Ethereum: - No asynchronous state risks between chain operations - No wrapped token complexity or liquidity fragmentation - No artificial constraints on capital deployment - No settlement uncertainty affecting execution ## Build with us The best way to get started is with our [docs]({{< relref "/docs/learn-about-signet/simplifying-the-rollup/" >}}) or [getting in touch](http://t.me/anthspezzano) if you have any questions. **Get Involved:** - [Developer interest form](https://forms.gle/abc123) - [Documentation feedback](https://forms.gle/xyz789) **Market Participants:** - [Filler examples](https://github.com/init4tech/signet-sdk/tree/main/crates/rpc/examples): Complete implementation patterns **Order System:** - [Orders in Signet]({{< relref "/docs/build-on-signet/signet-to-ethereum/orders/" >}}): Permit2 orders in Signet - [SDK primitives](https://github.com/init4tech/signet-sdk/tree/main/crates/types): Type-safe order handling **Bundle Construction:** - [Atomic execution](https://github.com/init4tech/signet-sdk/tree/main/crates/bundle): Transaction sequencing tools - [Simulation framework](https://github.com/init4tech/signet-sdk/tree/main/crates/sim): Pre-execution validation -------------------------------------------------------------------------------- ### Execution Engine URL: https://signet.sh/updates/execution-engine/ Published: 2025-04-30 -------------------------------------------------------------------------------- Signet uses a straightforward order system for cross-chain transactions. We remove unnecessary verification layers to deliver faster settlements with lower costs. Our architecture focuses on reliable asset transfers between networks without technical complexity. The order system uses _signed orders_ to describe a user's intent and _bundles_ to coordinate execution of these intents across chains. ## Conditional transactions via signed orders Signed orders use the Permit2 standard, allowing users to authorize token transfers with a single signature. This intent mechanism powers Signet's swaps, allowing users to express intents like: > "I want to swap 1 ETH on Signet for 1800 USDC on Ethereum" Nothing happens if the exact conditions you specify are not met. ```rust // Signed orders pub struct SignedOrder { /// The permit batch. #[serde(flatten)] pub permit: Permit2Batch, /// The desired outputs. pub outputs: Vec, } // Permit2 batches pub struct Permit2Batch { pub permit: ::RustType, pub owner: Address, pub signature: Bytes, } ``` Permit2 batches contain individually signed transactions, allowing multiple inputs (what the user provides) to map to desired outputs (what the user receives). These Permit2 transactions then go to an orders cache for matching. ## Cross-chain transfers Signet's approach to cross-chain transfers separates mechanisms based on direction. This separation creates predictable pathways that optimize for each direction's unique requirements. ### Entering Signet: Passage For asset transfers from Ethereum to Signet, users will interact with the Passage contract, which follows a simple event-based approach: 1. User deposits assets to the Passage contract on Ethereum 2. The contract emits an Enter event 3. Signet observes this event and mints corresponding tokens ### Exiting Signet: Signed Orders For asset transfers from Signet to Ethereum, users will use signed orders (swaps). 1. Signed orders express user intent to move assets from Signet to Ethereum 2. Market participants fulfill these orders with corresponding assets 3. Execution happens atomically in the same block on both chains {{< image src="cross-chain-swap.png" alt="Cross-chain swap diagram showing token flow between chains" >}} ## Market Participants Our market-based approach eliminates the need for verification periods or complex bridging. Users move assets instantly between chains. {{< image src="signet-architecture.png" alt="Signet architecture diagram showing system components" >}} ### Searchers Searchers connect orders with liquidity and are essential for creating efficient markets. They: - Scan orders cache - Build matching permits into bundles - Submit these bundles to block builders - Drive efficiency by connecting orders with liquidity ### Fillers Fillers provide liquidity to the system. They: - Fulfill open orders with their own assets - Enable cross-chain transfers without traditional bridges - Make instant withdrawals possible ### Block Builders Block builders assemble transactions into Signet blocks. They process two primitive types -- _bundles_ and _signed orders_. 1. Bundles are standard collections of transactions to be included in blocks. 4844 transactions are excluded from the rollup by design. 2. Signed Orders are permit2 transactions expressing user intents. These connect cross-chain activity via `hostFills`. ## Bundles coordinate cross-chain actions We extend [Flashbots bundles](https://docs.flashbots.net/flashbots-auction/advanced/understanding-bundles) with a single field: `hostFills`. This connects Signet transactions with Ethereum actions: ```json { "txs": ["0xabc...", "0xdef..."], "blockNumber": "0x123", "hostFills": { "outputs": [...], "permit": { } } } ``` This extension enables atomic cross-chain execution --- the Signet transactions and the necessary host chain actions either all succeed together or the entire bundle fails. A Signet bundle includes: - An array of transactions (`txs`) - Block targeting information (`blockNumber`, `minTimestamp`, `maxTimestamp`) - Optional `revertingTxHashes` identifying Signet transactions allowed to revert without failing the whole bundle. - Optional `replacementUuid` for identifying updated bundles - The `hostFills` field containing required host chain actions (if any). Bundles come in two forms: 1. Bundles _with_ host fills contain signed orders requiring validation. The bundle builder tracks and validates these orders. Host fills are processed alongside bundle transactions. 2. Bundles _without_ host fills handle standard in-network activity. These contain regular Signet transactions and are processed like standard transaction lists. When building systems that handle real value, reliability isn't optional. That's why we've adopted flashbots-style bundle standards: 1. Transactions execute exactly as specified 2. All operations succeed or none happen 3. Transactions only revert when explicitly marked as revertible ## Build with us We're building the simplest and most pragmatic rollup. If you're interested or have feedback, please reach out: - [Developer interest form](https://www.notion.so/1bb3e1cd453981829c41cfc0a005aecf?pvs=21) - [Documentation feedback form](https://www.notion.so/1b33e1cd453981a88fabf6fb6c89f052?pvs=21) -------------------------------------------------------------------------------- ### Instrumentation (for Rust Ethereum) URL: https://signet.sh/updates/instrumentation-for-rust-ethereum/ Published: 2025-10-16 -------------------------------------------------------------------------------- Like a lot of things I write, this post is motivated by my own past mistakes. I've worked on a lot of Rust projects over the last five years. Along the way, I've had the opportunity to work with many extremely talented Rust developers, and get a deep look into the Rust Ethereum ecosystem. At this point, if you are using Ethereum, you likely use or rely on my work. I am self-taught. I think this is true for many Rust Ethereum developers. I have a bachelor's in Japanese and no experience with software development in large companies. I've never had a Rust mentor or teacher, although I've learned an incredible amount from my peers and collaborators. Being self-taught comes with some baggage, of course. We don't have the same exposure to the tools and best-practices that are common in enterprises, and we tend not to have experience operating large-scale systems. As part of the work we're doing at init4 on [Signet](https://signet.sh/), we started deploying a lot of systems, and investing heavily in observability. While doing that, I discovered all the mistakes we made while writing [alloy](http://github.com/alloy-rs/alloy), and (as I do) formed some strong opinions about tracing. Hopefully by writing them down, I can save everyone else a bit of time and a lot of headaches. ## Tracing vs Logging So first of all, what is tracing? "Tracing" is best understood as a way of recording information about a program's execution, in a structured way. It is an evolution of, and improvement on, traditional logging. Developers are familiar with logging. We're used to console debugging like `println!("what the heck is {}, {}", x, y);` and logging is a natural extension of that. We add log lines to our code, and then we can see what happened when we ran the program. This works great for individuals, or in small programs, but it doesn't scale well to large systems. There are a few problems that prevent logging from scaling up. The most annoying for me are the following: 1. Logs are discrete, while systems are continuous. 2. Logs are localized, while systems are distributed. 3. Log data is text, while system data is structured. 4. Logs are isolated, while system events are related. ### So what do these mean? #### Logs are _discrete_, while systems are _continuous_ A program runs continuously, and we want to understand what it is doing over time. Logs are discrete events, and we have to infer the program's behavior from a series of log lines. This is hard, and often impossible. To correct this, tracing's core primitive is not the event, but the **span**. A span represents a unit of work, and has a start and end time. Spans can be nested, and we can see the relationships between spans. This gives us a much richer understanding of what the program is doing. #### Logs are _isolated_, while system events are _related_ Logs are just a series of unrelated events, and a reader has to infer the relationships between them. Tracing spans are nested by default, and events are associated with a specific set of spans. This makes it much easier to understand the relationships between events. Filtering events by the span that contains them is a powerful way to understand the behavior of a system. #### Logs are _localized_, while systems are _distributed_ Logs are generated by a single program, and localized to the machine that the program is running on. In a distributed system, we have many programs running on many machines, and we want to understand how they interact. Tracing standards allow correlation of events across service boundaries(!!!). E.g. the [traceparent](https://www.w3.org/TR/trace-context/) header standard allows correlation of events between different system components communicating over HTTP. Properly-instrumented systems can be traced end-to-end, even when they are distributed across many services. #### Log data is _text_, while system data is _structured_ Logs are just text, and we have to parse them to extract useful information. This is hard, and often impossible. Tracing data is structured, and we can attach arbitrary key-value pairs to spans and events. This makes it much easier to extract useful information. Structured data allows consumers to filter, aggregate, and analyze the data in powerful ways. If we can stop thinking of tracing as "better logging", and start thinking of it as critical infrastructure for understanding complex systems, our software will be more maintainable, more mature, and more ready for institutional use. ## Thinking about tracing Our goal is to implement good tracing, and then to configure our program to output traces in useful ways. These ways _may include logging_, but **tracing is distinct from and more important than logging.** When we trace a program well, we get informative logging for free, in addition to powerful visualizations, performance information, and a suite of industry-standard telemetry tools. In order to that, we have to update our mental model from logging to tracing. The core primitive of a tracing is the **span**. Spans represent a timed portion of program execution, and contain metadata about the work being done. E.g. a span may represent a single HTTP request, and contain the HTTP Method, the route, and the length of the body in bytes. Spans should be: - **time-limited**—at most a few seconds. - **work-associated**—a specific action the program is taking. - **informative**—have useful data attached to them, and not over-verbose. ![An example trace showing nested spans](image1.png) Spans are hierarchical. This means that spans may have a parent, siblings, children, etc. When your traces are exported, you can explore relationships between spans. A common mistake we make is thinking of tracing as oriented towards **events**. Unlike spans, events are easy to see and think about. An event corresponds to a single logical line of code. Events represent a single point in time. They are associated with the currently-open span tree. We often think of events as log lines, but it's better to think of them as a notable point in time that _we might be interested in._ Whether this results in a log line or not is a separate point of configuration. As developers, we tend to focus on events because they are easier to understand. They correspond nicely to console-output debugging, which is the friendliest most comforting tool a developer has. However, events do not help in understanding the flow of execution. They leave huge gaps that spans cover. Events without spans are not useful. Observability exists to answer complex questions. When tracing a distributed system we're not trying to figure out if a bus stopped at your street. We want to know where it is on its route, how it got there, and what the average time between stops is. Spans cover this data, while events don't. Events are an important part of your instrumentation. We use them to know whether critical sections have been passed, and what the state of the system was at that point in time. To make them useful, events should be: - **informative**—have useful data attached to them, and not over-verbose. - **descriptive**—the message should be clear and concise. - **lifecycle-aware**—events should be used to record the lifecycle of a unit of work. - **non-repetitive**—the event should fire ONCE in its span's lifetime. ## Distributed Tracing The goal of instrumenting code is to allow us to observe its behavior both in specific instances, and in aggregate. We want to be able to see how it behaved in a specific run, and we want to be able to see how it behaves across many runs. In other words, just creating the span data is not enough. We need to observe it. This requires not only development, but operations. I'll avoid going in depth on this, but expect a followup post. Developers need to understand two main things: **Distributed Tracing** as a concept and **OpenTelemetry**. The core idea of distributed tracing is that systems are not isolated programs. They are complex sets of microservices or components, and data may move across many of them as part of a logical task. Distributed tracing systems therefore need to collect traces from several different places, aggregate the information, correlate the traces (e.g. by creating span hierarchies that include spans from different programs running on different machines), and expose them to queries. An entire industry of tools like [Honeycomb](https://www.honeycomb.io/) and [Groundcover](https://www.groundcover.com/) (init4's current preferred provider) have sprung up, in addition to open-source tooling like [Jaeger](https://www.jaegertracing.io/) and [Zipkin](https://zipkin.io/). Here's a pretty simple span trace from our Groundcover setup: ![A distributed trace visualization showing multiple service spans](image2.png) In order to move traces from your components to your distributed tracing provider, you need a standard serialization of trace data. The industry has largely settled on [OpenTelemetry](https://opentelemetry.io/). OpenTelemetry (OTEL) provides a set of standards for creating and maintaining traces, as well as the OpenTelemetry Protocol (OTLP) for sending trace data over a network. OpenTelemetry provides a set of [semantic conventions](https://opentelemetry.io/docs/concepts/semantic-conventions/) to standardize trace contents over broad ranges of application types. E.g. [ajj](http://github.com/init4tech/ajj) implements the [semantic conventions for a JSON-RPC server](https://opentelemetry.io/docs/specs/semconv/rpc/json-rpc/). Rust has good libraries for OpenTelemetry, and integrations between OTEL, OTLP, and the tokio tracing ecosystem. ## Back to Crypto So back to my past mistakes. I've written a lot of code that treats tracing as logging, and I've approved a lot of PRs that do the same. This code is ubiquitous in the ecosystem. I did this because I did not understand tracing. I'm writing this because **I now believe that distributed tracing ought to be mandatory for production software.** Until our clients, libraries, etc have strong span-oriented instrumentation, they are not ready for institutional deployment. All software is work-in-progress, crypto software doubly so. You do not have to ship with a perfectly instrumented codebase. We can improve our code over time, span by span. At this point, if you want some hands-on content, check out our [teaching-tracing](https://github.com/init4tech/teaching-tracing) repo. Which contains all the code you need to create and instrument binaries, as well as bad examples, gotchas, and a bunch of very legible documentation. [Reach out to us on twitter](https://x.com/signetsh) if this was helpful 🙂 -------------------------------------------------------------------------------- ### Solidity Examples URL: https://signet.sh/updates/solidity-examples/ Published: 2025-08-14 -------------------------------------------------------------------------------- Cross-chain execution traditionally requires bridges, callbacks, and waiting periods. Signet's Orders system provides an alternative approach where fillers compete to satisfy same-block atomic actions. Signet Orders specify inputs and outputs same-chain or cross-chain. Rather than building complex bridge infrastructure, applications can post Orders that market participants fulfill based on the opportunities they unlock. Fillers might satisfy an Order not just for direct profit, but because it opens opportunities across Signet or Ethereum. This creates a competitive marketplace where execution value extends beyond the immediate Order into more sophisticated designs. ### Implementation The [signet-sol](https://github.com/init4tech/signet-sol) repository demonstrates how Orders work in practice, from flash loans that don't require liquidity pools to payment systems that operate without msg.value. ### Auto-Configuration Applications inherit automatic system configuration across networks through chain ID detection, eliminating manual address management and enabling immediate Order functionality. ```solidity // SignetStd.sol - Base contract with auto-configuration contract SignetStd { // Auto-configures addresses based on deployment chain constructor() { if (block.chainid == PecorinoConstants.ROLLUP_CHAIN_ID) { HOST_CHAIN_ID = PecorinoConstants.HOST_CHAIN_ID; PASSAGE = PecorinoConstants.PECORINO_ROLLUP_PASSAGE; ORDERS = PecorinoConstants.PECORINO_ROLLUP_ORDERS; // ... token addresses configured automatically } } // Helper functions for creating structured orders function makeInput(address token, uint256 amount) internal pure returns (RollupOrders.Input memory); function hostUsdcOutput(uint256 amount, address recipient) internal view returns (RollupOrders.Output memory); function hostEthOutput(uint256 amount, address recipient) internal view returns (RollupOrders.Output memory); } ``` [*github.com/init4tech/signet-sol/SignetStd.sol*](https://github.com/init4tech/signet-sol/blob/main/src/SignetStd.sol) Deploy the same contract code across all networks without modification. ### Flash Loans Orders enable flash loans through just-in-time liquidity from competitive fillers, removing the need for pre-existing liquidity pools. ```solidity // Flash.sol - provides flash modifier abstract contract Flash is SignetStd { modifier flash(address asset, uint256 amount) { _; // Output is received *before* the modified function is called RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1); outputs[0] = makeRollupOutput(asset, amount, address(this)); // Input is sent back after the modified function RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1); inputs[0] = makeInput(asset, amount); ORDERS.initiate( block.timestamp, // this is equivalent to no deadline inputs, outputs ); } } ``` [*github.com/init4tech/signet-sol/Flash.sol*](https://github.com/init4tech/signet-sol/blob/main/src/Flash.sol) ### Payment Gates Orders allow contracts to require payments without directly managing funds, creating market-driven execution gates. ```solidity // PayMe.sol - payment gate implementation abstract contract PayMe is SignetStd { modifier payMe(uint256 amount) { _; demandPayment(NATIVE_ASSET, amount); } modifier payMeSubsidizedGas(uint256 amount) { uint256 pre = gasleft(); uint256 gp = tx.gasprice; _; uint256 post = gasleft(); uint256 loot = amount - (gp * (pre - post)); demandPayment(NATIVE_ASSET, loot); } function demandPayment(address asset, uint256 amount) internal { RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1); outputs[0] = makeRollupOutput(asset, amount, address(this)); ORDERS.initiate( block.timestamp, new RollupOrders.Input[](0), // no inputs outputs ); } } ``` [*github.com/init4tech/signet-sol/PayMe.sol*](https://github.com/init4tech/signet-sol/blob/main/src/PayMe.sol) Turn execution costs into revenue opportunities for fillers. ### Incentivized Execution Applications can offer bounties for function execution, turning computational costs into revenue opportunities for fillers. ```solidity // PayYou.sol - bounty-driven execution abstract contract PayYou is SignetStd { modifier paysYou(uint256 tip) { _; providePayment(NATIVE_ASSET, tip); } modifier paysYourGas(uint256 tip) { uint256 pre = gasleft(); uint256 gp = tx.gasprice; _; uint256 post = gasleft(); uint256 loot = tip + (gp * (pre - post)); providePayment(NATIVE_ASSET, loot); } function providePayment(address asset, uint256 amount) internal { RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1); inputs[0] = makeInput(asset, amount); ORDERS.initiate{value: amount}( block.timestamp, // no deadline inputs, new RollupOrders.Output[](0) // no outputs ); } } ``` [*github.com/init4tech/signet-sol/PayYou.sol*](https://github.com/init4tech/signet-sol/blob/main/src/PayYou.sol) Post a bounty Order before executing computation. Fillers compete to claim the reward by calling the function, creating an execution scheduling system. ### Instant Exits Orders enable immediate rollup exits through market makers who provide instant L1 liquidity in exchange for small fees. ```solidity // GetOut.sol - immediate exit mechanism contract GetOut is SignetStd { error MissingValue(); receive() external payable { getOut(); } function getOut() public payable { require(msg.value > 0, MissingValue()); uint256 desired = msg.value * 995 / 1000; // 0.5% fee RollupOrders.Input[] memory inputs = new RollupOrders.Input[](1); inputs[0] = makeInput(NATIVE_ASSET, msg.value); RollupOrders.Output[] memory outputs = new RollupOrders.Output[](1); outputs[0] = hostUsdcOutput(desired, msg.sender); ORDERS.initiate{value: msg.value}( block.timestamp, inputs, outputs ); } } ``` [*github.com/init4tech/signet-sol/GetOut.sol*](https://github.com/init4tech/signet-sol/blob/main/src/GetOut.sol) ### Implications Order execution happens atomically within a single block, from submission through settlement. Signet makes cross-chain synchronous composability possible. MEV capture becomes application-directed. Applications can design for their MEV rather than blindly leaking it. Capital efficiency improves through demand-driven liquidity. Flash loans come from competitive filler inventory rather than idle or unproductive pool reserves. ### Rethinking Rollups Signet improves how cross-chain applications are built. Instead of building around the limitations of third party bridges and asynchronous messaging, applications benefit from instant cross-chain execution. Signet enables entirely new categories of applications— from flash loans without pools to payment gates without cash flow management. [Signet-sol](https://github.com/init4tech/signet-sol) is just the beginning of what we can offer. Signet's Orders system turns cross-chain operations into first-class primitives, enabling cross-chain simplicity and composability. **Build with Signet:** - [Testnet Faucet](https://www.gas.zip/faucet/signet) for testnet USD - [Orders Documentation](https://signet.sh/docs/build-on-signet/smart-contracts/orders/overview/) for technical specifications - [Example Contracts](https://github.com/init4tech/signet-sol) for all implementation patterns Feedback? Find us on [Twitter](https://twitter.com/signetsh) or [Telegram](https://t.me/anthspezzano).