Onchain Sequencing Modules

Modular smart contracts for customizable transaction ordering, permissions, auctions, and cross-chain coordination

Syndicate transforms blockchain sequencing by bringing it onchain through smart contracts deployed on a separate blockchain. This modular approach enables unprecedented control, transparency, and community ownership of the transaction ordering process.

How Onchain Sequencing Works

┌───────────┐      ┌────────────────────────┐      ┌───────────┐      ┌────────────┐
│           │      │ Sequencing Chain       │      │           │      │            │
│  Users &  │─────▶│ ┌────────────────────┐ │─────▶│ Execution │─────▶│ Settlement │
│   Apps    │      │ │ Sequencing Modules │ │      │   Engine  │      │   Layer    │
│           │      │ └────────────────────┘ │      │           │      │            │
└───────────┘      └────────────────────────┘      └───────────┘      └────────────┘
  1. Users submit transactions to the appchain's mempool
  2. Sequencing modules on the sequencing chain control permissions, ordering, auctions, and atomic execution
  3. The execution engine processes transactions in the determined order
  4. The settlement layer finalizes state with periodic commitments

This architecture decouples transaction ordering from execution, enabling innovation in sequencing while maintaining compatibility with existing execution environments.

Sequencing Module Components

Metabased sequencing modules are comprised of several key components that can be independently configured to meet your specific application needs.

Permission Modules

Permission modules control who can sequence transactions on your appchain. They implement a simple interface with an isAllowed function that returns whether an address can sequence:

function isAllowed(address proposer) external view returns (bool);

Available Modules

  • Allowlist: Simple admin-controlled list of allowed sequencers
  • Token Balance: Require sequencers to hold a minimum amount of tokens
  • Sealed Bid Auction: Competitive bidding for sequencing rights

Example: Token Balance Module

Here's a simple example that requires sequencers to hold tokens:

contract TokenBalanceSequencingModule is PermissionModule {
    address public immutable tokenAddress;
    uint256 public immutable minimumBalance;
 
    function isAllowed(address proposer) external view override returns (bool) {
        return IERC20(tokenAddress).balanceOf(proposer) >= minimumBalance;
    }
}

Ordering Modules

The ordering of transactions is currently handled by the base MetabasedSequencerChain contract, which processes transactions in the order they are submitted. This provides a simple and predictable transaction ordering mechanism.

Available Features

  • Single Transaction Processing: Process individual transactions through processTransaction
  • Bulk Transaction Processing: Process multiple transactions at once with processBulkTransactions
  • Raw Transaction Support: Handle compressed transactions with processTransactionRaw

Example: Transaction Processing

contract MetabasedSequencerChain is SequencingModuleChecker {
    event TransactionProcessed(address indexed sender, bytes data);
    
    function processTransaction(bytes calldata data) external onlyWhenAllowed(msg.sender) {
        emit TransactionProcessed(msg.sender, prependZeroByte(data));
    }
    
    function processBulkTransactions(bytes[] calldata data) external onlyWhenAllowed(msg.sender) {
        for (uint256 i = 0; i < data.length; i++) {
            emit TransactionProcessed(msg.sender, prependZeroByte(data[i]));
        }
    }
}

Auction Modules

Auction modules enable competitive sequencing rights through sealed-bid auctions, where bidders submit encrypted bids to ensure fairness.

Available Modules

  • Sealed Bid Auction: A two-phase auction where bidders first submit encrypted bids and later reveal them

Example: Sealed Bid Auction

contract SealedBidAuctionSequencingModule is PermissionModule {
    // Track bids and auction state
    mapping(address => bytes32) public sealedBids;
    address public highestBidder;
    uint256 public highestBid;
    
    // Phase 1: Submit sealed bids
    function bid(bytes32 sealedBid) external payable {
        require(msg.value > 0, "Must send deposit");
        sealedBids[msg.sender] = sealedBid;
    }
    
    // Phase 2: Reveal bids
    function revealBid(uint256 bidAmount, string memory salt) external {
        bytes32 computedHash = keccak256(abi.encodePacked(bidAmount, salt));
        require(computedHash == sealedBids[msg.sender], "Invalid bid reveal");
        
        if (bidAmount > highestBid) {
            highestBid = bidAmount;
            highestBidder = msg.sender;
        }
    }
 
    // Only highest bidder can sequence
    function isAllowed(address proposer) external view override returns (bool) {
        return proposer == highestBidder;
    }
}

Atomic Modules

Atomic modules enable coordinated transaction processing across multiple chains, ensuring all transactions are processed together or none at all.

Available Modules

  • Atomic Sequencer: Process transactions across multiple chains atomically

Example: Atomic Sequencer

contract AtomicSequencer {
    // Process transactions on multiple chains atomically
    function processTransactionsAtomically(
        MetabasedSequencerChain[] chains,
        bytes[] transactions
    ) external {
        // Ensure input arrays match
        require(chains.length == transactions.length, "Length mismatch");
        
        // Process each transaction on its respective chain
        for (uint256 i = 0; i < chains.length; i++) {
            chains[i].processTransaction(transactions[i]);
        }
    }
    
    // Process multiple transactions per chain atomically
    function processBulkTransactionsAtomically(
        MetabasedSequencerChain[] chains,
        bytes[][] transactions
    ) external {
        require(chains.length == transactions.length, "Length mismatch");
        
        for (uint256 i = 0; i < chains.length; i++) {
            chains[i].processBulkTransactions(transactions[i]);
        }
    }
}

The atomic sequencer ensures that either all transactions are processed successfully across all specified chains, or none are processed at all. This is useful for cross-chain operations that need to maintain consistency.

Working with Modules

Select Existing Modules

Choose from our production-ready modules:

CategoryModuleDescriptionBest For
PermissionAllowlistAdmin-controlled access listTesting, private networks, controlled rollouts
PermissionToken BalancePermission based on token holdingsToken-gated sequencing, economic security
PermissionAlways AllowedOpen access for testingDevelopment and testing
AuctionSealed BidCompetitive bidding for sequencing rightsMarket-based sequencer selection
AtomicAtomic SequencerCross-chain transaction coordinationComplex multi-chain operations

Build Custom Modules

Here are modules you can build using our interfaces:

CategoryModuleDescriptionBest For
PermissionDAO VotingCommunity-governed sequencer selectionDecentralized governance
PermissionMulti-SigMultiple approval requirementsHigh-security applications
PermissionReputationPermission based on past performanceQuality-focused networks
PermissionTime-LockScheduled sequencing rightsPredictable rotation
OrderingFee PriorityOrder by gas priceRevenue optimization
OrderingRandomRandomized transaction orderingMEV protection
OrderingBatch AuctionTime-window based orderingFair price discovery
OrderingDynamic SizeAdaptive batch sizingNetwork optimization
AuctionDutchDecreasing price auctionsQuick price discovery
AuctionEnglishIncreasing price auctionsMaximum value extraction
AuctionContinuousRolling auction periodsConstant availability

Compose Modules

Combine modules to create sophisticated sequencing solutions using our factory contract:

// Deploy the factory
MetabasedFactory factory = new MetabasedFactory();
 
// Create a RequireAll module for combining multiple checks
RequireAllModule permissions = RequireAllModule(
    factory.createAllContractsWithRequireAllModule(
        admin,
        manager,
        l3ChainId,
        salt
    ).permissionModule
);
 
// Add permission checks
permissions.addCheck(
    address(new TokenBalanceSequencingModule(token, minBalance)),
    true // add to head of list
);
permissions.addCheck(
    address(new AllowlistSequencingModule(admin)),
    false // add to tail of list
);

Composition Features

  • RequireAll: All checks must pass (AND logic)
  • RequireAny: At least one check must pass (OR logic)
  • Linked List Structure: Checks are stored in an ordered list
  • Dynamic Updates: Add or remove checks at runtime
  • Admin Control: Only admin can modify composition

Getting Started

  1. Choose Your Modules: Review the available modules and select those that match your security, fairness, and performance requirements. If needed, plan custom modules to meet specific needs.

  2. Implement Custom Logic: Build new modules by implementing our interfaces and test them thoroughly using our development tools.

  3. Configure Your Chain: Deploy and initialize your chain with the selected modules.

  4. Monitor and Upgrade: Track performance metrics and upgrade modules as needed using our modular architecture to ensure optimal chain operation.